DEV Community

Cover image for Getting Started with n8n Automation for Developers
Devashish Sharma
Devashish Sharma

Posted on

Getting Started with n8n Automation for Developers

Getting Started with n8n Automation for Developers

You have a cron job that scrapes a pricing page and dumps the output into a Postgres table. It’s been running in a Docker container on a $5 DigitalOcean droplet for eight months. Yesterday, marketing asked if that data could also hit a Slack channel and trigger a HubSpot lead update whenever a competitor drops their price by more than ten percent.

You could spend your afternoon writing a Node app, wiring up the Slack SDK, parsing OAuth tokens for HubSpot, building a retry queue for when their API inevitably returns a 503, and setting up Datadog alerts so you know when it breaks at 3 AM.

Or you could drag three boxes on a canvas, map some JSON, and be done in twenty minutes.

That is why I finally gave in and started using n8n. I used to write off visual workflow builders as Zapier-style toy tools meant for product managers who don't know the difference between a string and an integer. But n8n is self-hostable, handles arbitrary JavaScript/TypeScript nodes, and doesn't charge you per step execution if you run it on your own hardware.

Here is how to get it running and actually build something useful without losing your mind.

Spinning up the local stack

The easiest way to kick the tires is Docker Compose. Don't bother trying to run it natively via npm unless you enjoy debugging SQLite locking issues and missing native module binaries.

Create a docker-compose.yml file somewhere on your machine:

version: "3.8"

volumes:
  n8n_data:

services:
  n8n:
  image: n8nio/n8n:latest
  restart: always
  ports:
    - "5678:5678"
  volumes:
    - n8n_data:/home/node/.n8n
  environment:
    - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
Enter fullscreen mode Exit fullscreen mode

Run docker compose up -d and navigate to http://localhost:5678. It'll ask you to create an owner account. Local storage is handled via an internal SQLite database by default, which is fine for local testing, though you'll want to swap that for PostgreSQL if you push this to production.

One quick gotcha right out of the gate: if you are trying to test webhooks locally from services running on your host machine (like a local Postgres or an Express app), localhost inside the n8n Docker container resolves to the container itself, not your machine. Use host.docker.internal instead of localhost when defining connection strings inside your workflows. I spent an embarrassing forty minutes wondering why a Postgres node couldn't reach port 5432 before remembering how Docker networking works.

Writing actual code inside the nodes

The killer feature of n8n—what separates it from the SaaS alternatives—is that you aren't boxed into rigid UI dropdowns. When you need to transform data, you drop in a Code node and write JavaScript or Python.

Let's say you have an incoming webhook payload from a GitHub pull request, and you want to extract specific fields, normalize a date, and calculate the size of the diff before sending it downstream.

Here is what a standard JavaScript code node looks like inside n8n. You have access to an items array, which contains the incoming data objects:

// n8n Code Node (JavaScript)
const results = [];

for (const item of $input.all()) {
  const pr = item.json.pull_request;

  if (!pr) {
    continue;
  }

  // Calculate some custom metrics
  const titleLength = pr.title.length;
  const isDraft = pr.draft;
  const createdDate = new Date(pr.created_at).toISOString();

  results.push({
    json: {
      prId: pr.id,
      author: pr.user.login,
      titleLength,
      isDraft,
      createdDate,
      processedAt: new Date().toISOString()
    }
  });
}

return results;
Enter fullscreen mode Exit fullscreen mode

Notice the return structure. Every item returned must be wrapped in an object containing a json key. If you just return a flat array of standard JavaScript objects, n8n will throw an unhelpful execution error and you'll be back staring at the console logs.

You can also pull in external npm packages by setting the N8N_ENV_APPDATA or using environment variables to configure allowed modules, though for most data shaping, standard JS built-ins are more than enough.

Error handling and retries without writing boilerplate

In a traditional codebase, handling transient network failures means writing try/catch blocks, exponential backoff logic, and setting up dead-letter queues.

In n8n, this is handled at the node configuration level.

Click on any node—say, an HTTP Request node calling a flaky third-party API—and open its settings. You can configure:

  • On Error: Continue (ignore failure), Stop Workflow, or Retry Node.
  • Max Tries: How many times to attempt the request before failing.
  • Wait Between Tries: Delay in milliseconds.

If you want a dedicated fallback path, you can draw a second error-handling branch directly from the node. If the primary HTTP node throws a 5xx error, you can route execution to an alternate node that drops a warning into a specific Discord or Slack channel.

It feels a bit weird at first—managing control flow visually rather than through code—but when you are debugging a complex chain of API calls at 4 PM on a Friday, being able to visually trace the exact path an errored payload took through the system beats digging through distributed log aggregators.

Version control and deployment reality checks

Let's address the elephant in the room: how do you deploy and version control a visual workflow?

If you just build workflows in the UI of your production server, you are one misclicked drag-and-drop away from an outage with zero git history.

n8n solves this by storing workflows as JSON. You can export them manually, or use the n8n CLI/API to sync them to a Git repository. When running via Docker, you can configure community packages or use n8n's built-in project features if you're on their managed tiers, but for self-hosters, the standard pattern is using the REST API to pull workflow JSON files and commit them to GitHub.

One thing that tripped me up early on: credential IDs. If you export a workflow JSON that contains references to a Postgres credential or a GitHub OAuth token, those credential IDs are tied to your specific database instance. If you import that JSON into a fresh n8n instance, the workflow will break because the target credential ID doesn't exist there.

When moving workflows between environments (local to staging to production), you either need to re-map the credentials in the UI after import, or handle authentication dynamically via headers in standard HTTP nodes using environment variables rather than n8n's built-in credential manager.

Next steps

Stop reading about it and kill that cron job you hate maintaining.

Pull down the Docker Compose file, spin up an instance, and migrate one small, annoying internal script—like an alert notifier or a data sync job—into a single n8n workflow. See how it feels to write the transformation logic in a code node while letting the tool handle the HTTP transport and retries.

Top comments (0)