Every n8n workflow eventually hits the same wall: the data from one node doesn’t match what the next node expects. Field names are wrong. Values need transformation. You need three fields from a response that returns twenty. The Edit Fields node exists specifically to solve this problem.
Also known as the Set node (its original name), the Edit Fields node is arguably the most frequently used transformation node in n8n. It sits between your data sources and destinations, reshaping information so everything connects smoothly. Yet despite its fundamental importance, most users only scratch the surface of what it can do.
The Data Transformation Bottleneck
You pull customer data from an API. The response includes firstName, lastName, and emailAddress. But your CRM expects first_name, last_name, and email. Without transformation, your workflow fails.
Or you receive a webhook payload with 50 fields. You only need 5 for your database insert. Passing everything through wastes resources and creates confusion about what data actually matters.
These scenarios happen constantly in automation work. The Edit Fields node handles them all without writing a single line of JavaScript.
What the Edit Fields Node Actually Does
The Edit Fields node lets you:
- Create new fields with static values or dynamic expressions
- Rename existing fields to match expected formats
- Extract specific fields while discarding everything else
- Transform values using expressions and JavaScript methods
- Build complex objects with nested structures and arrays
Think of it as a data filter and transformer combined. Data flows in, you define what comes out, and the node handles the rest.
What You’ll Learn
- How to choose between Manual Mapping and JSON Output modes
- Step-by-step configuration for both modes
- The dot notation behavior that trips up most users
- Key options like “Keep Only Set Fields” and when to use them
- Real-world examples you can adapt to your workflows
- How to troubleshoot the most common Edit Fields issues
- When to use Edit Fields versus the Code node
When to Use the Edit Fields Node
Before diving into configuration, understand when this node is the right choice.
| Scenario | Best Choice | Why |
|---|---|---|
Rename fields (e.g., firstName to first_name) | Edit Fields | Simple mapping, no code needed |
| Extract 5 fields from a 30-field response | Edit Fields | ”Keep Only Set Fields” option handles this |
| Add a static value to every item | Edit Fields | Basic field creation |
| Complex conditional logic with loops | Code node | Edit Fields lacks programming constructs |
| Mathematical calculations on values | Either | Edit Fields supports expressions for simple math |
| Build nested JSON with dynamic keys | JSON Output mode | Handles complex structures |
| Transform array items individually | Code node | Loop logic requires programming |
| Merge data from multiple previous nodes | Edit Fields | Can reference multiple nodes via expressions |
Rule of thumb: Start with Edit Fields. If you find yourself fighting the interface or needing loops and conditionals, switch to the Code node. Most data transformations don’t require code.
Understanding the Two Modes
The Edit Fields node offers two distinct approaches to configuring your output. Choosing the right mode saves time and reduces errors.
Manual Mapping Mode
Best for: Most use cases. Field renaming, extraction, simple transformations.
Manual Mapping provides a visual interface where you drag fields from the input panel, set field names, choose data types, and configure expressions. Each field you want in the output gets its own row.
Advantages:
- Visual feedback shows exactly what you’re mapping
- Type selection helps catch errors early
- Drag-and-drop makes field references easy
- Easier to maintain for team members who don’t know JSON
Limitations:
- Creating deeply nested objects requires multiple fields
- Arrays need JSON Output mode or careful expression work
- Large numbers of fields can make the interface cluttered
JSON Output Mode
Best for: Complex nested structures, arrays, programmatic JSON construction.
JSON Output mode lets you write raw JSON with embedded expressions. Instead of configuring individual fields, you define the entire output structure at once.
Advantages:
- Full control over output structure
- Native array and nested object support
- Easier to copy/paste from API documentation
- Better for complex transformations
Limitations:
- No visual type checking
- JSON syntax errors stop the workflow
- Harder for non-technical team members to modify
Mode Comparison
| Feature | Manual Mapping | JSON Output |
|---|---|---|
| Visual interface | Yes | No |
| Drag-and-drop | Yes | No |
| Type selection | Yes | No |
| Nested objects | Limited | Full support |
| Arrays | Via expressions | Native support |
| Learning curve | Lower | Higher |
| Debugging | Easier | Harder |
| Best for | Field mapping | Complex structures |
Manual Mapping Deep Dive
Most Edit Fields usage happens in Manual Mapping mode. Here’s how to use it effectively.
Step 1: Add the Node
- Open your workflow in n8n
- Click + to add a node
- Search for “Edit Fields” (or “Set” in older versions)
- Connect it to your data source
Step 2: Configure Fields
With Manual Mapping selected as the mode:
- Click Add Field
- Enter the output field name in the Name input
- Set the Value using expressions or static values
- Choose the appropriate Type (string, number, boolean, etc.)
Step 3: Map from Input
The fastest way to map fields is drag-and-drop:
- Look at the INPUT panel on the left showing data from the previous node
- Click and hold a field name
- Drag it to the Value input of your field
- n8n automatically creates the expression
{{ $json.fieldName }}
Fixed vs Expression Values
Each field value has a toggle between Fixed and Expression modes.
Fixed mode: The value you enter is used literally. If you type hello, the output is the string hello.
Expression mode: The value is evaluated as an n8n expression. Type {{ $json.greeting }} to pull the greeting field from input data.
Common mistake: Entering $json.name in Fixed mode. This outputs the literal string $json.name, not the value of the name field. Always use Expression mode for dynamic values.
Type Selection
Choosing the right type matters for downstream nodes:
- String: Text values, always safe but may need conversion later
- Number: Numeric values, parsed from strings if needed
- Boolean: True/false values
- Array: Lists of items
- Object: Nested structures
If you’re unsure, String works for most cases. Use our expression validator tool to test values before running the full workflow.
Common Manual Mapping Mistakes
Mistake 1: Forgetting expression brackets
Wrong: $json.email
Right: {{ $json.email }}
Mistake 2: Wrong node reference
Wrong: {{ $json.orderID }} (when data comes from a different node)
Right: {{ $('HTTP Request').item.json.orderID }}
Mistake 3: Accessing nested properties incorrectly
Wrong: {{ $json.customer.email }} (if customer might be undefined)
Right: {{ $json.customer?.email }} (optional chaining)
JSON Output Mode Deep Dive
When Manual Mapping feels limiting, JSON Output mode provides full control over your data structure.
When to Choose JSON Output
- Building API request bodies with specific structures
- Creating arrays with multiple items
- Matching complex webhook payload formats
- Working with deeply nested objects
- Programmatically generating field names
Basic JSON Output Structure
Switch the Mode to JSON and enter your structure:
{
"customerName": "{{ $json.name }}",
"customerEmail": "{{ $json.email }}",
"source": "n8n automation"
}
The output includes all three fields, with customerName and customerEmail pulled from input data and source set to a static value.
Arrays in JSON Output
JSON Output mode handles arrays naturally:
{
"tags": ["automation", "n8n", "workflow"],
"orderItems": [
{
"id": "{{ $json.item1_id }}",
"quantity": {{ $json.item1_qty }}
},
{
"id": "{{ $json.item2_id }}",
"quantity": {{ $json.item2_qty }}
}
]
}
Note: Numbers don’t need quotes around the expression. {{ $json.item1_qty }} outputs the raw number.
Dynamic Arrays from Input
To transform an input array into an output array, you need to reference it carefully:
{
"processedItems": {{ JSON.stringify($json.items.map(item => ({
"name": item.title,
"price": item.cost
}))) }}
}
For complex array transformations, the Code node is often cleaner.
Nested Object Example
Creating nested structures for API compatibility:
{
"contact": {
"firstName": "{{ $json.first_name }}",
"lastName": "{{ $json.last_name }}",
"email": "{{ $json.email_address }}"
},
"metadata": {
"source": "website_form",
"timestamp": "{{ $now.toISO() }}",
"processed": true
}
}
If your JSON has syntax issues, try our JSON fixer tool to identify and correct problems before running the workflow.
Key Options Explained
The Edit Fields node includes several options that dramatically change its behavior. Understanding these prevents common frustrations.
Keep Only Set Fields
What it does: When enabled, the output contains ONLY the fields you explicitly define. All other input fields are discarded.
When to enable:
- Sending data to an API that rejects unknown fields
- Database inserts with specific column requirements
- Reducing payload size for performance
- Ensuring only expected data passes through
When to disable (Include All Input Fields):
- Enriching existing data with additional fields
- Adding calculated values while preserving original data
- Debugging to see what data flows through
Default behavior: Input fields are included unless you enable “Keep Only Set Fields.”
Include Binary Data
What it does: Controls whether binary data (files, images) from previous nodes passes through.
Enable when:
- Processing files that need to reach downstream nodes
- Working with images, PDFs, or other attachments
- The next node expects binary data
Disable when:
- Binary data isn’t needed and wastes memory
- You’re only working with JSON data
For distributed n8n setups using queue mode, binary data handling requires additional configuration for proper worker access.
Ignore Type Conversion Errors
What it does: Allows the node to continue even when type conversions fail (e.g., converting “hello” to a number).
Enable when:
- Data quality varies and you want processing to continue
- You have downstream error handling
- Testing workflows with incomplete data
Disable when:
- Data integrity is critical
- You need immediate failure feedback
- Production workflows where bad data should stop execution
Support Dot Notation
This option deserves its own section because it causes significant confusion.
Dot Notation: The Hidden Gotcha
This single feature causes more Edit Fields confusion than any other. Understanding it prevents hours of debugging.
Default Behavior
By default, n8n interprets dots in field names as nested object paths. If you set a field named user.email with value [email protected], the output is:
{
"user": {
"email": "[email protected]"
}
}
Not:
{
"user.email": "[email protected]"
}
When This Causes Problems
Problem 1: API expects literal dot in field name
Some APIs use dots in field names without implying nesting. If you need custom.field as a literal key, dot notation breaks your integration.
Problem 2: Unexpected object creation
You’re renaming customer_email to customer.email expecting a simple rename. Instead, you get a nested customer object with an email property.
Problem 3: Conflicting structures
Setting both user.name and user.email creates one user object with two properties. Setting user as a string and user.email creates conflicts.
How to Disable Dot Notation
- Open the Edit Fields node
- Click Add Option
- Select Support Dot Notation
- Set it to Off
Now user.email creates a field literally named user.email:
{
"user.email": "[email protected]"
}
Code Example: Dot Notation On vs Off
Input data:
{
"firstName": "John",
"lastName": "Doe"
}
Field configuration:
- Name:
contact.name - Value:
{{ $json.firstName }} {{ $json.lastName }}
Output with Dot Notation ON (default):
{
"contact": {
"name": "John Doe"
}
}
Output with Dot Notation OFF:
{
"contact.name": "John Doe"
}
Choose based on what your downstream integration expects.
Working with Expressions
Expressions make the Edit Fields node powerful. Here’s how to use them effectively.
Accessing Previous Node Data
Current node’s input:
{
{
$json.fieldName;
}
}
Specific previous node:
{
{
$("Node Name").item.json.fieldName;
}
}
First item from a node:
{
{
$("Node Name").first().json.fieldName;
}
}
For complex expression patterns, see our n8n expressions guide.
Fallback Values
Handle missing data gracefully with the nullish coalescing operator:
{
{
$json.email ?? "[email protected]";
}
}
If email is null or undefined, the fallback value is used.
Optional Chaining for Nested Properties
Prevent errors when accessing nested properties that might not exist:
{
{
$json.customer?.address?.city ?? "Unknown";
}
}
Common Expression Patterns
String concatenation:
{
{
$json.firstName + " " + $json.lastName;
}
}
Number formatting:
{
{
Number($json.price).toFixed(2);
}
}
Date transformation:
{
{
$now.toISO();
}
}
{
{
new Date($json.timestamp).toISOString();
}
}
Conditional value:
{
{
$json.amount > 100 ? "large" : "small";
}
}
Test expressions before running your workflow using our expression validator.
Real-World Examples
Example 1: Renaming Fields for API Compatibility
Scenario: Your CRM webhook sends firstName, lastName, emailAddress. Your marketing platform expects first_name, last_name, email.
Configuration:
- Mode: Manual Mapping
- Keep Only Set Fields: Enabled
| Name | Value | Type |
|---|---|---|
| first_name | {{ $json.firstName }} | String |
| last_name | {{ $json.lastName }} | String |
{{ $json.emailAddress }} | String |
Output:
{
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]"
}
Example 2: Extracting Specific Fields for Database Insert
Scenario: API returns 30 fields. Your database table has 5 columns.
Configuration:
- Mode: Manual Mapping
- Keep Only Set Fields: Enabled
Map only the fields your database needs:
| Name | Value | Type |
|---|---|---|
| id | {{ $json.customer_id }} | String |
| name | {{ $json.full_name }} | String |
{{ $json.primary_email }} | String | |
| status | {{ $json.account_status }} | String |
| created_at | {{ $json.registration_date }} | String |
The other 25 fields are automatically excluded.
Example 3: Creating Nested Objects for Webhook Payloads
Scenario: Third-party API expects a specific nested structure.
Configuration:
- Mode: JSON Output
{
"event": "customer_signup",
"timestamp": "{{ $now.toISO() }}",
"customer": {
"id": "{{ $json.id }}",
"profile": {
"name": "{{ $json.name }}",
"email": "{{ $json.email }}"
}
},
"source": {
"platform": "n8n",
"workflow": "Customer Onboarding"
}
}
Example 4: Combining Data from Multiple Nodes
Scenario: Merge customer data from CRM lookup with order data from e-commerce webhook.
Configuration:
- Mode: Manual Mapping
- Keep Only Set Fields: Enabled
| Name | Value | Type |
|---|---|---|
| order_id | {{ $('Webhook').item.json.orderId }} | String |
| order_total | {{ $('Webhook').item.json.total }} | Number |
| customer_name | {{ $('CRM Lookup').item.json.name }} | String |
| customer_email | {{ $('CRM Lookup').item.json.email }} | String |
| customer_tier | {{ $('CRM Lookup').item.json.membership_tier }} | String |
The output combines data from both nodes into a single clean object.
Troubleshooting Common Issues
Problem: Preview Shows Value but Output Is Empty
Symptoms: The expression editor shows the correct value, but when you test the node or run the workflow, the field is empty or missing.
Causes and fixes:
-
Expression vs Fixed mode mismatch
- Check the toggle next to your value field
- Expressions need Expression mode enabled
-
Input data differs between test and execution
- Preview uses pinned or cached data
- Real execution uses live data from previous nodes
- Verify the data structure matches
-
Async timing issues
- Previous node hasn’t completed when Edit Fields runs
- Check node connections and execution order
-
Keep Only Set Fields enabled unexpectedly
- If disabled, check if another node is filtering
Use the workflow debugger to identify exactly where data is lost.
Problem: Different Behavior Test vs Production
Symptoms: “Execute step” shows correct output, but “Execute workflow” produces different results.
Causes and fixes:
-
Different input data
- Test step may use pinned data from a previous test
- Production uses live data that differs
- Unpin data and test with real inputs
-
Node execution order
- Full workflow execution may run nodes differently than expected
- Check that all dependencies complete before Edit Fields runs
-
Expression evaluation timing
$nowgives different times in test vs production- Data from other nodes may not be available
Problem: Type Conversion Errors
Symptoms: Workflow fails with type conversion errors on specific fields.
Causes and fixes:
-
String value set as Number type
- Change field type to String
- Or pre-process to ensure numeric values
-
Null values in typed fields
- Use fallback values:
{{ $json.amount ?? 0 }} - Or enable “Ignore Type Conversion Errors”
- Use fallback values:
-
Object where primitive expected
- Drill into the object:
{{ $json.data.value }}not{{ $json.data }}
- Drill into the object:
Problem: Binary Data Not Passing Through
Symptoms: Files or images from previous nodes don’t appear in downstream nodes.
Causes and fixes:
-
Include Binary Data option disabled
- Open node options and enable “Include Binary Data”
-
Keep Only Set Fields stripping binary
- Binary data is separate from JSON fields
- Enabling “Include Binary Data” alongside “Keep Only Set Fields” preserves files
-
Queue mode with filesystem storage
- Distributed workers need shared binary storage
- See queue mode configuration for S3 setup
Problem: Unexpected Nested Structure
Symptoms: Output has nested objects when you expected flat fields, or vice versa.
Cause: Dot notation behavior (covered in detail above).
Fix: Add the “Support Dot Notation” option and set it to Off if you need literal dots in field names.
Edit Fields vs Code Node
Knowing when to switch from Edit Fields to the Code node saves time and frustration.
| Task | Edit Fields | Code Node |
|---|---|---|
| Rename 5 fields | Ideal | Overkill |
| Filter to specific fields | Ideal | Overkill |
| Add calculated field | Works for simple math | Better for complex logic |
| Transform every array item | Difficult | Ideal |
| Conditional field inclusion | Limited | Full flexibility |
| Dynamic field names | Possible but awkward | Straightforward |
| Validate data format | No | Yes |
| Call external functions | No | Yes |
Switch to Code Node When
- You need loops - Iterating over arrays with custom logic
- Complex conditionals - Multiple if/else branches affecting structure
- Data validation - Checking formats, ranges, required fields
- String manipulation - Complex regex, parsing, extraction
- Multiple transformations - Easier to read as code than many expression fields
Stay with Edit Fields When
- Simple mapping - Direct field-to-field transfers
- Basic transformations - Concatenation, simple math
- Team maintenance - Non-coders can understand the visual interface
- Quick prototyping - Faster to configure than writing code
Pro Tips and Best Practices
1. Name Your Nodes Descriptively
Instead of “Edit Fields” or “Set,” use names that describe the transformation: “Format for CRM API” or “Extract Order Fields.”
This helps when debugging and when teammates read your workflow.
2. Test with Pinned Data
Before connecting to live data sources, pin sample data to the previous node. This lets you iterate on your Edit Fields configuration without triggering real API calls.
3. Use Keep Only Set Fields for Clean Outputs
When sending data to external systems, explicitly define every field. This prevents accidental data leakage and makes payloads predictable.
4. Handle Missing Data Gracefully
Always use optional chaining (?.) and fallback values (??) for fields that might not exist:
{
{
$json.user?.email ?? "[email protected]";
}
}
5. Split Complex Transformations
Instead of one Edit Fields node doing 15 things, use multiple nodes with clear purposes:
- “Extract Customer Fields”
- “Format Dates”
- “Build API Payload”
This improves readability and makes debugging easier.
6. Document with Sticky Notes
Add sticky notes in n8n explaining why specific transformations exist, especially for non-obvious field mappings or business logic.
7. Check JSON Structure Before API Calls
Before the HTTP Request node, add an Edit Fields node to construct the exact payload format. This separates data transformation from API communication.
8. Validate Complex Outputs
For critical workflows, add a downstream node that validates the Edit Fields output before proceeding. This catches transformation errors early.
For more workflow design patterns, see our workflow testing guide which covers validation strategies and debugging techniques.
Frequently Asked Questions
What’s the difference between Manual Mapping and JSON Output?
Manual Mapping provides a visual interface where you add fields one by one, drag values from input, and select data types. It’s ideal for most transformations, especially field renaming and extraction. JSON Output lets you write raw JSON with embedded expressions, giving full control over nested structures and arrays. Choose Manual Mapping for simplicity and maintainability. Choose JSON Output when you need complex nested structures or are matching a specific API format. Most users should start with Manual Mapping and only switch to JSON Output when the visual interface becomes limiting.
Why does my Edit Fields node show the correct value in preview but output nothing?
This typically happens for three reasons. First, check that Expression mode is enabled (not Fixed mode) for dynamic values. The toggle next to the value field controls this. Second, verify that the input data during workflow execution matches what you see in the preview. Preview often uses cached or pinned data that differs from live execution. Third, check for timing issues where the previous node hasn’t completed when Edit Fields runs. To debug, add a temporary node after Edit Fields that logs all output, or use the execution log to see exactly what data passed through. Our workflow debugger tool can help identify where data is lost.
How do I prevent dot notation from creating nested objects?
By default, n8n interprets dots in field names as nested paths. So user.email creates {"user": {"email": "value"}} instead of {"user.email": "value"}. To use literal dots, click Add Option in the Edit Fields node, select Support Dot Notation, and set it to Off. Now field names with dots are treated as literal strings. This is essential when working with APIs that expect dots in their field names without implying nested structures. Always check your downstream system’s requirements before deciding whether to enable or disable this option.
Can I use the Edit Fields node to merge data from multiple nodes?
Yes. In expressions, you can reference any previous node using $('Node Name').item.json.fieldName syntax. Create fields that pull from different nodes: one field from your webhook, another from an API lookup, a third from a database query. All values combine into a single output object. The key is knowing the exact node names and ensuring those nodes have completed before the Edit Fields node runs. For complex merges involving arrays or conditional logic, consider whether the Merge node or Code node might be more appropriate.
When should I use Edit Fields vs the Code node for data transformation?
Use Edit Fields when you’re renaming fields, extracting specific properties, adding static or simply calculated values, and building basic nested objects. It’s faster to configure, easier to maintain, and readable by non-coders. Switch to the Code node when you need loops over arrays, complex conditional logic, string parsing with regex, data validation, or when you’re fighting the Edit Fields interface to achieve something that would take five lines of JavaScript. A good heuristic: if you’ve spent more than 10 minutes trying to make Edit Fields work, the Code node will probably be faster. See our JavaScript Code node guide for Code node patterns and examples.