Data arrives in chaos. API responses come back in whatever order the server felt like returning them. Spreadsheet exports preserve the random sequence someone entered rows. Webhook payloads deliver records as they happened, not as you need them.
Without control over order, your workflows process items unpredictably. Reports display data inconsistently. Users see different results on each run.
The Sort node brings order to this chaos. It takes the items flowing through your workflow and arranges them according to rules you define:
- Alphabetically by name
- Numerically by price
- Chronologically by date
- Randomly for A/B testing
The sorted data continues downstream, processed in exactly the sequence your logic requires.
The Data Order Problem
Most data sources return records in arbitrary order. Your CRM might return contacts by internal ID. An e-commerce API might sort orders by creation timestamp. A database query without an ORDER BY clause returns whatever the engine finds first.
This creates problems when order matters:
- Leaderboards need highest scores first
- Reports should show newest transactions at the top
- Priority queues must process urgent items before routine ones
- Pagination displays need consistent ordering across pages
You could add sorting to every API call and database query. But what happens when you combine data from multiple sources? Or when the source offers no sorting options? The Sort node handles these cases within your workflow, giving you control regardless of upstream limitations.
What the Sort Node Does
The Sort node reorders items in your workflow:
- Sorts by any field including nested properties like
customer.address.city - Supports multiple sort types for different use cases (simple, random, custom code)
- Handles multiple fields for complex ordering (sort by category, then by name within each category)
- Works with all data types including strings, numbers, dates, and booleans
- Processes efficiently without modifying your original data structure
The sorted items flow out in your specified order, ready for downstream nodes that depend on sequence. For the official reference, see the n8n Sort node documentation.
What You’ll Learn
- When to use the Sort node versus the Code node for ordering data
- How to configure all three sort types: Simple, Random, and Code
- Multi-field sorting for complex ordering requirements
- JavaScript patterns for custom sort logic (numeric, date, locale-aware)
- Common mistakes that produce unexpected order and how to fix them
- Real-world sorting patterns you can adapt immediately
When to Use the Sort Node
Before configuring sort options, understand when the Sort node is the right choice versus alternatives.
| Scenario | Best Choice | Why |
|---|---|---|
| Sort items by a single field (name, date, price) | Sort node (Simple mode) | Quick visual configuration, no code needed |
| Randomize item order for testing | Sort node (Random mode) | Built-in shuffle functionality |
| Sort by multiple fields with same direction | Sort node (Simple mode) | Add multiple fields to sort by |
| Sort by multiple fields with different directions | Sort node (Code mode) | Custom logic needed for mixed ascending/descending |
| Complex sorting with business logic | Code node | Full JavaScript control for advanced requirements |
| Sort array values within a single field | Code node or expressions | Sort node operates on items, not arrays inside items |
| Sort after removing duplicates | Sort node after Remove Duplicates | Chain nodes for data cleanup pipelines |
| Sort before aggregating into single output | Sort node before Aggregate | Control final array order |
Rule of thumb: Use the Sort node’s Simple mode for straightforward single or multi-field sorting. Switch to Code mode when you need numeric sorting, custom date handling, or mixed sort directions. Use the Code node when sorting logic requires business rules beyond basic field comparisons.
Understanding Sort Types
The Sort node offers three distinct modes. Each serves different use cases and requires different configuration.
Simple Mode
The default mode for everyday sorting tasks. You specify which fields to sort by and whether each should be ascending or descending.
Best for:
- Alphabetical ordering (A to Z or Z to A)
- Date ordering (oldest to newest or newest to oldest)
- Single or multiple field sorting
- Quick setup without writing code
Configuration:
- Set Type to “Simple”
- Click Add Field To Sort By
- Enter the Field Name (e.g.,
name,createdAt,order.total) - Select Order: Ascending or Descending
- Add more fields if needed for secondary sorting
Important: Simple mode uses JavaScript’s default string comparison. This means numbers sort lexicographically: “100” comes before “2” because the character “1” comes before “2”. For true numeric sorting, use Code mode.
Random Mode
Shuffles items into a random order. Each execution produces a different sequence.
Best for:
- A/B testing and experiments
- Random sampling from datasets
- Shuffle order for variety (playlist-style randomization)
- Fair distribution when order might create bias
Configuration:
- Set Type to “Random”
- No additional configuration needed
- Run the workflow to see shuffled output
Code Mode
Write custom JavaScript to control exactly how items compare during sorting.
Best for:
- Numeric sorting (proper number comparison, not string comparison)
- Date sorting with custom formats
- Multi-field sorting with different directions per field
- Locale-aware alphabetical sorting
- Complex business logic (priority levels, custom hierarchies)
Configuration:
- Set Type to “Code”
- Write a JavaScript comparator function in the Code field
- The function receives two items (
aandb) and returns a number
The comparator function must return:
- Negative number:
ashould come beforeb - Zero:
aandbare equal (order unchanged) - Positive number:
ashould come afterb
Sort Type Comparison
| Feature | Simple | Random | Code |
|---|---|---|---|
| Configuration | Visual (field + direction) | None | JavaScript code |
| Multiple fields | Yes (add more fields) | N/A | Yes (in comparator) |
| Numeric accuracy | No (lexicographic) | N/A | Yes (with proper logic) |
| Date handling | Basic (ISO strings work) | N/A | Full control |
| Mixed directions | No (all same direction) | N/A | Yes |
| Use case | Quick alphabetical/date | Randomization | Complex requirements |
Your First Sort
Walk through a practical example: sorting a list of contacts alphabetically by last name.
Step 1: Add the Sort Node
- Open your n8n workflow
- Click + to add a node
- Search for “Sort”
- Click to add it to your canvas
- Connect it to your data source (webhook, HTTP request, spreadsheet, etc.)
Step 2: Configure Simple Mode
With the Sort node selected:
- Confirm Type is set to “Simple” (the default)
- Click Add Field To Sort By
- Enter
lastNamein the Field Name field - Keep Order set to “Ascending” (A to Z)
Step 3: Test the Node
- If you have test data from previous executions, click Test step
- Examine the output panel
- Verify items now appear in alphabetical order by last name
Example input:
[
{ "firstName": "Carol", "lastName": "Zhang" },
{ "firstName": "Alice", "lastName": "Miller" },
{ "firstName": "Bob", "lastName": "Anderson" }
]
Sorted output:
[
{ "firstName": "Bob", "lastName": "Anderson" },
{ "firstName": "Alice", "lastName": "Miller" },
{ "firstName": "Carol", "lastName": "Zhang" }
]
Step 4: Connect Downstream Nodes
The Sort node has a single output. Connect your next nodes (send emails, update records, generate reports) knowing that all items will arrive in the order you specified.
Simple Mode Deep Dive
Simple mode handles most sorting scenarios without code. Here is how to configure it for various requirements.
Single Field Sorting
The most common case: order items by one property.
Ascending (A to Z, lowest to highest, oldest to newest):
Field Name: name
Order: Ascending
Descending (Z to A, highest to lowest, newest to oldest):
Field Name: createdAt
Order: Descending
Multiple Field Sorting
When items share the same value for your primary sort field, secondary fields break the tie.
Example: Sort products by category, then alphabetically by name within each category.
Field 1: category (Ascending)
Field 2: name (Ascending)
Input:
[
{ "category": "Electronics", "name": "Laptop" },
{ "category": "Books", "name": "Novel" },
{ "category": "Electronics", "name": "Camera" },
{ "category": "Books", "name": "Manual" }
]
Output:
[
{ "category": "Books", "name": "Manual" },
{ "category": "Books", "name": "Novel" },
{ "category": "Electronics", "name": "Camera" },
{ "category": "Electronics", "name": "Laptop" }
]
Books come before Electronics (alphabetically), and within each category, items are sorted by name.
Dot Notation for Nested Fields
Access nested properties using dot notation:
Field Name: customer.address.city
Order: Ascending
This reaches into nested objects:
{
"orderId": 123,
"customer": {
"name": "Alice",
"address": {
"city": "Boston",
"state": "MA"
}
}
}
The Sort node finds customer.address.city = “Boston” and uses it for comparison.
Disabling Dot Notation
If your field names actually contain periods (uncommon but possible), disable dot notation:
- Open Options in the Sort node
- Toggle off Dot Notation
With dot notation disabled, my.field.name looks for a literal property called my.field.name rather than navigating into nested objects.
Simple Mode Limitations
Simple mode cannot handle:
- Numeric sorting: The number 100 sorts before 2 (lexicographic comparison)
- Mixed directions: All fields sort the same direction
- Custom date formats: Non-ISO dates may not sort correctly
- Case-insensitive sorting: “apple” and “Apple” sort differently
For these requirements, use Code mode.
Code Mode: Custom JavaScript Sorting
Code mode gives you complete control over how items compare during sorting. You write a JavaScript comparator function that receives two items and returns which should come first.
Comparator Function Basics
Your code receives two parameters: a and b, representing two items being compared.
Return:
- Negative number (typically -1):
acomes beforeb - Zero:
aandbare equal, keep original order - Positive number (typically 1):
bcomes beforea
Basic structure:
// Access item data via a.json and b.json
const valueA = a.json.fieldName;
const valueB = b.json.fieldName;
// Compare and return result
if (valueA < valueB) return -1;
if (valueA > valueB) return 1;
return 0;
Numeric Sorting
The most common Code mode use case: sorting numbers as numbers, not strings.
Problem with Simple mode:
Input: [{ "price": 100 }, { "price": 2 }, { "price": 50 }]
Simple mode result: 100, 2, 50 (wrong - lexicographic)
Solution with Code mode:
return a.json.price - b.json.price;
Subtracting produces the correct result:
- If
a.priceis smaller, result is negative (a first) - If
b.priceis smaller, result is positive (b first) - If equal, result is zero (unchanged)
Result: 2, 50, 100 (correct numeric order)
For descending order, reverse the subtraction:
return b.json.price - a.json.price;
Date Sorting
Sort by Date objects for accurate chronological ordering:
Newest first (descending):
return new Date(b.json.createdAt) - new Date(a.json.createdAt);
Oldest first (ascending):
return new Date(a.json.createdAt) - new Date(b.json.createdAt);
This handles ISO date strings, timestamps, and most common date formats.
Multi-Criteria Sorting with Mixed Directions
Sort by category ascending, then by price descending within each category:
// First compare by category (ascending = A-Z)
if (a.json.category < b.json.category) return -1;
if (a.json.category > b.json.category) return 1;
// Categories are equal, compare by price (descending = highest first)
return b.json.price - a.json.price;
Case-Insensitive Sorting
Compare strings without case sensitivity:
const nameA = a.json.name.toLowerCase();
const nameB = b.json.name.toLowerCase();
if (nameA < nameB) return -1;
if (nameA > nameB) return 1;
return 0;
Now “apple”, “Apple”, and “APPLE” are treated as equal for sorting purposes.
Locale-Aware Sorting
For proper alphabetical sorting with accented characters and language-specific rules, use Intl.Collator:
const collator = new Intl.Collator('en', { sensitivity: 'base' });
return collator.compare(a.json.name, b.json.name);
This handles:
- Accented characters (e vs. e vs. e)
- Language-specific sort orders
- Case and diacritic options
Handling Undefined Values
When fields might be missing, handle undefined values explicitly:
const valueA = a.json.priority ?? 999;
const valueB = b.json.priority ?? 999;
return valueA - valueB;
This assigns a high number (999) to items without a priority, pushing them to the end.
Using nullish coalescing (??) provides defaults only for null or undefined, not for zero or empty strings.
Custom Priority Order
Sort by a predefined order rather than alphabetical:
const priorityOrder = { 'urgent': 1, 'high': 2, 'medium': 3, 'low': 4 };
const orderA = priorityOrder[a.json.priority] ?? 999;
const orderB = priorityOrder[b.json.priority] ?? 999;
return orderA - orderB;
Items sort by your custom priority hierarchy, not alphabetically.
Common Mistakes and How to Fix Them
These issues cause the most confusion when working with the Sort node, based on common questions from the n8n community.
Mistake 1: Lexicographic vs Numeric Sorting
Symptom: Numbers sort incorrectly. 100 appears before 2. Prices show as 10, 100, 15, 2, 25 instead of 2, 10, 15, 25, 100.
Cause: Simple mode compares values as strings. In string comparison, “1” comes before “2”, so “100” comes before “2”.
Fix: Use Code mode with numeric comparison:
return a.json.price - b.json.price;
Or convert strings to numbers in Simple mode using expressions in an Edit Fields node before sorting.
Mistake 2: Trying to Sort Nested Arrays
Symptom: The Sort node has no effect. Items come out in the same order they went in.
Cause: The Sort node sorts workflow items, not arrays within those items. If your HTTP request returns:
{
"objects": [
{ "id": 3, "name": "Charlie" },
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}
n8n sees this as one item containing an array. The Sort node cannot reach inside to reorder the objects array.
Fix: Use the Split Out node to expand the array into separate items before sorting:
- Split Out node: Field to Split Out =
objects - Sort node: Sort by
idascending - (Optional) Aggregate node to recombine if needed
Alternatively, use a Code node to sort the array in place:
items[0].json.objects.sort((a, b) => a.id - b.id);
return items;
Mistake 3: Date Format Issues
Symptom: Dates sort incorrectly. December appears before January. Dates from different years are mixed together.
Cause: Non-standard date formats sort as strings. “12/01/2023” (December) comes before “02/01/2024” (February) because “1” comes before “2”.
Fix: Use Code mode with proper Date parsing:
return new Date(a.json.date) - new Date(b.json.date);
For non-standard formats, parse explicitly:
// For "DD/MM/YYYY" format
const parseDate = (str) => {
const [day, month, year] = str.split('/');
return new Date(year, month - 1, day);
};
return parseDate(a.json.date) - parseDate(b.json.date);
Mistake 4: Case Sensitivity Problems
Symptom: Items with capital letters sort separately from lowercase. “Apple” appears in a different group than “banana” even though you expected alphabetical order.
Cause: Uppercase letters have lower ASCII values than lowercase. “A” (65) comes before “Z” (90), which comes before “a” (97).
Fix: Normalize case in Code mode:
return a.json.name.toLowerCase().localeCompare(b.json.name.toLowerCase());
Or use Intl.Collator with case-insensitive options:
const collator = new Intl.Collator('en', { sensitivity: 'accent' });
return collator.compare(a.json.name, b.json.name);
Mistake 5: Undefined Field Handling
Symptom: Some items disappear from the output, or the sort throws errors about undefined values.
Cause: Comparing undefined values produces unexpected results. undefined < "any string" is always false.
Fix: Handle missing fields with optional chaining and defaults:
const valueA = a.json.sortField ?? '';
const valueB = b.json.sortField ?? '';
return valueA.localeCompare(valueB);
For numbers:
const numA = a.json.priority ?? Infinity;
const numB = b.json.priority ?? Infinity;
return numA - numB;
Using Infinity pushes items with missing values to the end.
Real-World Examples
Example 1: Sort Orders by Date (Newest First)
Scenario: Display recent orders at the top of a dashboard or report.
Configuration (Code mode):
return new Date(b.json.orderDate) - new Date(a.json.orderDate);
Input:
[
{ "orderId": 1, "orderDate": "2024-01-15T10:00:00Z" },
{ "orderId": 2, "orderDate": "2024-03-20T14:30:00Z" },
{ "orderId": 3, "orderDate": "2024-02-10T09:15:00Z" }
]
Output:
[
{ "orderId": 2, "orderDate": "2024-03-20T14:30:00Z" },
{ "orderId": 3, "orderDate": "2024-02-10T09:15:00Z" },
{ "orderId": 1, "orderDate": "2024-01-15T10:00:00Z" }
]
Example 2: Sort Products by Price (Lowest First)
Scenario: Show the cheapest options first for price-conscious customers.
Configuration (Code mode):
return a.json.price - b.json.price;
Input:
[
{ "name": "Premium Widget", "price": 149.99 },
{ "name": "Basic Widget", "price": 29.99 },
{ "name": "Standard Widget", "price": 79.99 }
]
Output:
[
{ "name": "Basic Widget", "price": 29.99 },
{ "name": "Standard Widget", "price": 79.99 },
{ "name": "Premium Widget", "price": 149.99 }
]
Example 3: Random Shuffle for A/B Testing
Scenario: Randomize the order of email variants for unbiased testing.
Configuration:
- Set Type to “Random”
- No additional configuration needed
Each workflow execution produces a different random order, ensuring fair distribution across test variants.
Example 4: Multi-Field Sort (Category, then Name)
Scenario: Organize an inventory report by department, with items alphabetized within each department.
Configuration (Simple mode):
- Add field:
category(Ascending) - Add field:
name(Ascending)
Input:
[
{ "category": "Tools", "name": "Wrench" },
{ "category": "Electronics", "name": "Cable" },
{ "category": "Tools", "name": "Hammer" },
{ "category": "Electronics", "name": "Adapter" }
]
Output:
[
{ "category": "Electronics", "name": "Adapter" },
{ "category": "Electronics", "name": "Cable" },
{ "category": "Tools", "name": "Hammer" },
{ "category": "Tools", "name": "Wrench" }
]
Example 5: Custom Priority Order
Scenario: Support tickets should display by urgency level, not alphabetically.
Configuration (Code mode):
const priorityOrder = { 'critical': 1, 'high': 2, 'medium': 3, 'low': 4 };
return (priorityOrder[a.json.priority] ?? 5) - (priorityOrder[b.json.priority] ?? 5);
Input:
[
{ "ticketId": 101, "priority": "low" },
{ "ticketId": 102, "priority": "critical" },
{ "ticketId": 103, "priority": "medium" }
]
Output:
[
{ "ticketId": 102, "priority": "critical" },
{ "ticketId": 103, "priority": "medium" },
{ "ticketId": 101, "priority": "low" }
]
Pro Tips and Best Practices
1. Name Your Sort Nodes Descriptively
Replace generic names with descriptions of what the sort accomplishes:
- “Sort by Price (Low to High)”
- “Recent Orders First”
- “Alphabetize by Customer Name”
- “Randomize for Testing”
This makes workflows self-documenting and debugging much easier.
2. Test with Edge Cases
Before connecting to production systems, verify your sort handles:
- Empty strings and null values
- Duplicate values (should maintain relative order)
- Single item (should pass through unchanged)
- Already-sorted data (should remain stable)
- Boundary values (minimum and maximum values in your dataset)
Use pinned data to iterate quickly without re-running upstream nodes.
3. Consider Performance with Large Datasets
Sorting is efficient for most use cases, but very large datasets (thousands of items) may impact workflow execution time. For extremely large sorts:
- Filter data before sorting to reduce volume
- Consider whether the data source can return pre-sorted results
- Monitor execution time in production
4. Build Data Cleanup Pipelines
Combine Sort with other data transformation nodes for complete data preparation:
HTTP Request → Split Out → Filter → Sort → Remove Duplicates → Aggregate
This pattern cleans, organizes, and prepares data for downstream processing. See our guide on n8n data transformation for more pipeline patterns.
5. Use Expressions for Dynamic Sort Fields
When the sort field depends on earlier workflow data, use expressions in an Edit Fields node to prepare your data, or reference configuration from previous nodes in your Code mode comparator.
6. Document Complex Sort Logic
For Code mode sorts with business logic, add comments explaining the rules:
// Sort by priority first (urgent > high > medium > low)
// Then by age within each priority (oldest tickets first)
// Unassigned tickets always sort to the end
Future maintainers (including yourself) will thank you. Our workflow development services can help design robust sorting logic for complex requirements. For strategic guidance on workflow architecture, explore our consulting services.
Frequently Asked Questions
Why does sorting numbers give unexpected results like 100 before 2?
Simple mode sorts values as strings using lexicographic comparison. Characters are compared left to right: “1” (from “100”) comes before “2”, so “100” appears before “2”.
This is the standard behavior of JavaScript’s Array.sort() when no comparator is provided.
To sort numbers correctly, use Code mode with numeric comparison:
return a.json.price - b.json.price;
Subtraction produces negative, zero, or positive results that the sort algorithm interprets correctly. Alternatively, ensure your data contains actual number types rather than strings representing numbers.
How do I sort items by a date field?
For ISO format dates (like 2024-03-15T10:30:00Z), Simple mode usually works because ISO strings sort correctly as strings.
For other date formats or guaranteed accuracy, use Code mode:
// Ascending (oldest first)
return new Date(a.json.dateField) - new Date(b.json.dateField);
// Descending (newest first)
return new Date(b.json.dateField) - new Date(a.json.dateField);
The Date constructor parses most common formats automatically. For non-standard formats like “DD/MM/YYYY”, parse the string into date components manually before comparison.
Can I sort by multiple fields with different sort directions?
Yes, but only in Code mode. Simple mode applies the same direction (ascending or descending) to all fields.
In Code mode, you control each field’s direction independently. For example, to sort by category ascending and price descending:
// First compare categories (ascending)
if (a.json.category < b.json.category) return -1;
if (a.json.category > b.json.category) return 1;
// Categories match, compare prices (descending)
return b.json.price - a.json.price;
This gives you complete control over complex multi-criteria sorts.
How do I sort an array that exists inside a single workflow item?
The Sort node operates on workflow items, not arrays within items. If your data looks like { "results": [array of objects] }, the Sort node sees one item and cannot sort the internal array.
Option 1: Split, Sort, Recombine
Use the Split Out node to convert the array into separate items, sort them, then use the Aggregate node to recombine. This approach is visual and requires no code.
Option 2: Code Node
Use a Code node to sort the array in place:
items[0].json.results.sort((a, b) => a.name.localeCompare(b.name));
return items;
The Code node approach is more concise for simple cases.
What is the difference between sorting with the Sort node versus sorting in the Code node?
The Sort node is a dedicated visual tool for reordering workflow items. It provides three built-in modes (Simple, Random, Code) and handles the mechanics of sorting with a clear interface.
The Code node with JavaScript array.sort() offers maximum flexibility for any data manipulation, including:
- Sorting arrays within items
- Complex transformations
- Combining sort with other operations
Use the Sort node when reordering workflow items with standard patterns.
Use the Code node when you need to sort arrays inside items, when sort logic requires additional data processing, or when you prefer to consolidate multiple operations in one node.
For JavaScript patterns beyond sorting, see our n8n Code node JavaScript guide.