> ## Documentation Index
> Fetch the complete documentation index at: https://developer.upsun.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Scale n8n with PostgreSQL and Redis on Upsun

> Upgrade your n8n instance from SQLite to PostgreSQL and add Redis caching for better performance, 
scalability, and reliability. Step-by-step guide for Upsun.


export const PostMeta = ({data = {}}) => {
  const {author, date} = data;
  const authors = Array.isArray(author) ? author : author ? [author] : [];
  const resolveAuthor = slug => {
    const entry = AUTHOR_MAP[slug] || ({});
    const name = entry.name || slug;
    const github = entry.github || null;
    const linkedin = entry.linkedin || null;
    const url = github ? `https://github.com/${github}` : linkedin || null;
    const avatarUrl = github ? `https://github.com/${github}.png?size=64` : null;
    return {
      name,
      url,
      avatarUrl
    };
  };
  const formattedDate = date ? new Date(date).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  }) : null;
  if (authors.length === 0 && !formattedDate) return null;
  const AUTHOR_MAP = {
    "aaron-collier": {
      "name": "Aaron Collier"
    },
    "aaron-dudenhofer": {
      "name": "Aaron Dudenhofer"
    },
    "aaron-porter": {
      "name": "Aaron Porter"
    },
    "adriaan-odendaal": {
      "name": "Adriaan Odendaal"
    },
    "ajmal": {
      "name": "Ajmal Siddiqui"
    },
    "akalipetis": {
      "name": "Antonis Kalipetis"
    },
    "alexander-varwijk": {
      "name": "Alexander Varwijk"
    },
    "alicia-bevilacqua": {
      "name": "Alicia Bevilacqua"
    },
    "amelie-deguerry": {
      "name": "Amelie Deguerry"
    },
    "anacidre": {
      "name": "Ana Cidre",
      "linkedin": "https://www.linkedin.com/in/ana-cidre"
    },
    "andoni": {
      "name": "Andoni Auzmendi"
    },
    "andrei-taranu": {
      "name": "Andrei (Alex) Taranu",
      "linkedin": "https://www.linkedin.com/in/andrei-alex-taranu/"
    },
    "andrew-baxter": {
      "name": "Andrew Baxter"
    },
    "andrew-melck": {
      "name": "Andrew Melck"
    },
    "antoine-crochet-damais": {
      "name": "Antoine Crochet Damais"
    },
    "augustin-delaporte": {
      "name": "Augustin Delaporte",
      "linkedin": "https://www.linkedin.com/in/augustindelaporte/"
    },
    "branislav-bujisic": {
      "name": "Branislav Bujisic"
    },
    "carl-smith": {
      "name": "Carl Smith"
    },
    "caroline-leroy": {
      "name": "Caroline Leroy"
    },
    "cati-mayer": {
      "name": "Cati Mayer"
    },
    "catplat": {
      "name": "C Trinkwon"
    },
    "ceelolulu": {
      "name": "Celeste van der Watt"
    },
    "chadwcarlson": {
      "name": "Chad Carlson",
      "github": "chadwcarlson",
      "linkedin": "https://www.linkedin.com/in/chadwcarlson"
    },
    "chris-ward": {
      "name": "Chris Ward"
    },
    "chris-yates": {
      "name": "Chris Yates"
    },
    "christian-sieber": {
      "name": "Christian Sieber"
    },
    "christopher-lockheardt": {
      "name": "Christopher Lockheardt"
    },
    "christopher-skene": {
      "name": "Christopher Skene"
    },
    "chuck-morgan": {
      "name": "Chuck Morgan"
    },
    "corey-dockendorf": {
      "name": "Corey Dockendorf"
    },
    "crell": {
      "name": "Crell"
    },
    "damz": {
      "name": "Damz"
    },
    "dan-morrison": {
      "name": "Dan Morrison"
    },
    "davidbonachera": {
      "name": "David Bonachera",
      "github": "davidbonachera",
      "linkedin": "https://www.linkedin.com/in/davidbonachera"
    },
    "dereliahmet1": {
      "name": "Ahmet Faruk Dereli"
    },
    "devicezero": {
      "name": "Jonas Kröger",
      "github": "devicezero",
      "linkedin": "https://www.linkedin.com/in/jonaskroeger/"
    },
    "doug-goldberg": {
      "name": "Doug Goldberg"
    },
    "duncan-naves": {
      "name": "Duncan Naves",
      "github": "duncannaves",
      "linkedin": "https://www.linkedin.com/in/duncan-naves-a94423aa"
    },
    "erika-bustamante": {
      "name": "Erika Bustamante"
    },
    "fabpot": {
      "name": "Fabien Potencier"
    },
    "flovntp": {
      "name": "Florent Huck",
      "github": "flovntp",
      "linkedin": "https://www.linkedin.com/in/florenthuck"
    },
    "fred-plais": {
      "name": "Fred Plais"
    },
    "gauthier-garnier": {
      "name": "Gauthier Garnier"
    },
    "gilzow": {
      "name": "Paul Gilzow"
    },
    "gmoigneu": {
      "name": "Guillaume Moigneu",
      "github": "gmoigneu",
      "linkedin": "https://www.linkedin.com/in/guillaumemoigneu/"
    },
    "gregqualls": {
      "name": "Greg Qualls"
    },
    "guguss": {
      "name": "Augustin Delaporte"
    },
    "haylee-millar": {
      "name": "Haylee Millar"
    },
    "ivana-kotur": {
      "name": "Ivana Kotur"
    },
    "jackrabbithanna": {
      "name": "Mark Hanna"
    },
    "jared-wright": {
      "name": "Jared Wright",
      "github": "jww-sh",
      "linkedin": "https://www.linkedin.com/in/jaredwaynewright"
    },
    "jessica-orozco": {
      "name": "Jessica Orozco"
    },
    "joey-stanford": {
      "name": "Joey Stanford"
    },
    "john-grubb": {
      "name": "John Grubb"
    },
    "jonas-kruger": {
      "name": "Jonas Kruger"
    },
    "kathryn-frazer": {
      "name": "Kathryn Frazer"
    },
    "kemiojo": {
      "name": "Kemi Elizabeth Ojogbede"
    },
    "kieronsambrook-smith": {
      "name": "Kieronsambrook Smith"
    },
    "laurent-arnoud": {
      "name": "Laurent Arnoud",
      "linkedin": "https://www.linkedin.com/in/laurent-arnoud-861b44121/"
    },
    "letoya-boyne": {
      "name": "Letoya Boyne"
    },
    "lolautruche": {
      "name": "Jérôme Vieilledent"
    },
    "lyly-lepinay": {
      "name": "Lyly Lepinay"
    },
    "manauwar-alam": {
      "name": "Manauwar Alam"
    },
    "marc-antoine-porri": {
      "name": "Marc Antoine Porri"
    },
    "maria-antinkaapo": {
      "name": "Maria Antinkaapo"
    },
    "maria-de-anton": {
      "name": "Maria De Anton"
    },
    "mark-dorison": {
      "name": "Mark Dorison"
    },
    "markus-hausammann": {
      "name": "Markus Hausammann"
    },
    "mary-thomas": {
      "name": "Mary Thomas"
    },
    "mathias-bolt-lesniak": {
      "name": "Mathias Bolt Lesniak"
    },
    "mathieu-strauch": {
      "name": "Mathieu Strauch"
    },
    "matthias-van-woensel": {
      "name": "Matthias Van Woensel",
      "linkedin": "https://www.linkedin.com/in/matthias-van-woensel-267a069"
    },
    "maz-mohammadi": {
      "name": "Maz Mohammadi"
    },
    "michael-sharp": {
      "name": "Michael Sharp"
    },
    "mupsi": {
      "name": "Marine Gandy"
    },
    "natalie-harper": {
      "name": "Natalie Harper"
    },
    "ngommenginger": {
      "name": "Nicolas Gommenginger",
      "linkedin": "https://www.linkedin.com/in/nicolas-gommenginger"
    },
    "nicholas-bennison": {
      "name": "Nicholas Bennison"
    },
    "nicholas-vahalik": {
      "name": "Nicholas Vahalik"
    },
    "nick-hardiman": {
      "name": "Nick Hardiman"
    },
    "nickanderegg": {
      "name": "Nickanderegg"
    },
    "nicolas-grekas": {
      "name": "Nicolas Grekas",
      "github": "nicolas-grekas",
      "linkedin": "https://www.linkedin.com/in/nicolasgrekas/"
    },
    "niti-malwade": {
      "name": "Niti Malwade"
    },
    "opensocialteam": {
      "name": "Opensocialteam"
    },
    "ori-pekelman": {
      "name": "Ori Pekelman"
    },
    "otavio-santana": {
      "name": "Otavio Santana"
    },
    "palwandi": {
      "name": "Pawan Alwandi",
      "github": "pawpy",
      "linkedin": "https://www.linkedin.com/in/pawanalwandi"
    },
    "patrick-boest": {
      "name": "Patrick Boest"
    },
    "patrick-dawkins": {
      "name": "Patrick Dawkins",
      "github": "pjcdawkins",
      "linkedin": "https://www.linkedin.com/in/patrickdawkins"
    },
    "patrick-klima": {
      "name": "Patrick Klima"
    },
    "pjcdawkins": {
      "name": "Pjcdawkins"
    },
    "prineet-kaurbhurji": {
      "name": "Prineet Kaurbhurji"
    },
    "quentin-sinig": {
      "name": "Quentin Sinig"
    },
    "ralt": {
      "name": "Florian Margaine",
      "github": "ralt",
      "linkedin": "https://www.linkedin.com/in/florian-margaine-43971136"
    },
    "ramanathanramakrishnamurthy": {
      "name": "Ramanathanramakrishnamurthy"
    },
    "remi-lejeune": {
      "name": "Rémi Lejeune"
    },
    "ribel": {
      "name": "Taras Kruts"
    },
    "robert-douglass": {
      "name": "Robert Douglass"
    },
    "rudy-weber": {
      "name": "Rudy Weber"
    },
    "ryan-hicks": {
      "name": "Ryan Hicks"
    },
    "sabri-helal": {
      "name": "Sabri Helal"
    },
    "savannah-bergeron": {
      "name": "Savannah Bergeron"
    },
    "shannon-vettes": {
      "name": "Shannon Vettes"
    },
    "shawn-ogasawara": {
      "name": "Shawn Ogasawara",
      "linkedin": "https://www.linkedin.com/in/shawn-ogasawara-83a9a0/"
    },
    "shawna-spoor": {
      "name": "Shawna Spoor"
    },
    "shedrack-akintayo": {
      "name": "Shedrack Akintayo"
    },
    "simon-ruggier": {
      "name": "Simon Ruggier"
    },
    "sophie-van-der-kindere": {
      "name": "Sophie Van Der Kindere"
    },
    "stefanos-thampis": {
      "name": "Stefanos Thampis"
    },
    "stephen-weinberg": {
      "name": "Stephen Weinberg"
    },
    "sukhman-virk": {
      "name": "Sukhman Virk"
    },
    "sumaira-nazir": {
      "name": "Sumaira Nazir"
    },
    "sumer": {
      "name": "Sümer Cip"
    },
    "syed-raza": {
      "name": "Syed Raza"
    },
    "tamara-bacchia": {
      "name": "Tamara Bacchia"
    },
    "tara-arnold": {
      "name": "Tara Arnold"
    },
    "theosakamg": {
      "name": "Mickael Gaillard",
      "github": "theosakamg"
    },
    "thomasdiluccio": {
      "name": "Thomas di Luccio"
    },
    "tim-anderson": {
      "name": "Tim Anderson"
    },
    "tom-helmer-hansen": {
      "name": "Tom Helmer Hansen"
    },
    "tylermills": {
      "name": "Tyler Mills"
    },
    "upsun": {
      "name": "Upsun"
    },
    "veronika-tolkachova": {
      "name": "Veronika Tolkachova",
      "linkedin": "https://www.linkedin.com/in/veronika-tolkachova-169167a2"
    },
    "vince-parker": {
      "name": "Vince Parker"
    },
    "vinnie-russo": {
      "name": "Vincenzo Russo"
    },
    "vrobert78": {
      "name": "Vincent Robert",
      "github": "vrobert78",
      "linkedin": "https://www.linkedin.com/in/vincent-robert-498a883"
    },
    "yuriy-babenko": {
      "name": "Yuriy Babenko"
    },
    "yuriy-gerasimov": {
      "name": "Yuriy Gerasimov"
    }
  };
  return <div className="post-meta">
      {(authors.length > 0 || formattedDate) && <div className="post-meta-info">
          {authors.length > 0 && <div className="post-meta-authors">
              {authors.map(slug => {
    const {name, url, avatarUrl} = resolveAuthor(slug);
    const inner = <>
                    {avatarUrl && <img src={avatarUrl} alt={name} className="post-meta-avatar" />}
                    <span className="post-meta-author-name">{name}</span>
                  </>;
    return url ? <a key={slug} href={url} target="_blank" rel="noopener noreferrer" className="post-meta-author">
                    {inner}
                  </a> : <span key={slug} className="post-meta-author">{inner}</span>;
  })}
            </div>}
          {authors.length > 0 && formattedDate && <span className="post-meta-separator" aria-hidden="true">·</span>}
          {formattedDate && <span className="post-meta-date">{formattedDate}</span>}
        </div>}
    </div>;
};

<PostMeta data={{ date: "2026-04-29T10:00:00.000Z", author: ["flovntp"], date: "2026-04-29T12:00:00.000Z", image: "/images/posts/use-cases/n8n-upgrade-postgresql-redis/n8n-intro.png" }} />

In our [previous article](/posts/use-cases/n8n-saved-my-life), we showed how to host n8n on Upsun and automate your
workflows.
Since then, you might have noticed that your n8n instance is getting slower—especially if you're adding more complex
workflows or running frequent executions.

By default, [n8n uses SQLite](https://docs.n8n.io/hosting/configuration/supported-databases-settings/#self-hosted-n8n),
which works great for small setups but hits performance limits with high-volume workflows.
The good news? It's straightforward to upgrade to [PostgreSQL](/docs/add-services/postgresql) and add [Redis](/docs/add-services/redis) caching to unlock better performance and
scalability.

This guide walks you through the process.

## Why upgrade from SQLite?

**Performance limitations of SQLite**:

* SQLite has locking issues when multiple workflows execute simultaneously.
* Database queries slow down as your workflow history grows.
* No built-in clustering support—you're limited to a single instance.

**What PostgreSQL and Redis bring**:

* **PostgreSQL** provides a proper relational database with concurrent query support, better query optimization,
  and the ability to handle millions of executions.
* **Redis** acts as a caching layer and queue backend, reducing database load and speeding up workflow execution
  lookups.

## Prerequisites

Before you start, make sure you have:

* A working n8n instance on Upsun (follow [this tutorial](/posts/hands-on/nocode-n8n) if you don't have one yet).
* Access to your Upsun project via the CLI or console.
* Basic familiarity with [`.upsun/config.yaml` configuration](/docs/configure-apps/index#configure-apps).

## Architecture overview

Here's what your upgraded setup will look like:

<img src="https://mintcdn.com/upsun-c9761871/QvVRIdphS5yjjp2e/images/posts/use-cases/n8n-upgrade-postgresql-redis/n8n-architecture-stack.svg?fit=max&auto=format&n=QvVRIdphS5yjjp2e&q=85&s=fb3f78f34c0150cdc3c1e66efea57e0c" alt="Architecture Stack" width="690" height="530" data-path="images/posts/use-cases/n8n-upgrade-postgresql-redis/n8n-architecture-stack.svg" />

Key benefits of this architecture:

* **n8n main process** handles the web UI and API requests.
* **Worker processes** execute workflows independently, preventing long-running jobs from blocking the main application.
* **PostgreSQL** stores all workflow definitions, executions, credentials, and history.
* **Redis** manages the job queue, ensuring tasks are processed reliably and can be retried if needed.

## Step 1: Create an environment for PostgreSQL and Redis

As we never push major changes in production directly, we will first create a staging environment to test the new
configuration before applying it to production.

```bash title="Terminal" theme={null}
upsun branch add-postgresql-redis
```

This will create a new branch and environment named `add-postgresql-redis` where we will be able to test the new
configuration without affecting the production environment.

## Step 2: Add PostgreSQL and Redis services

First, update your `.upsun/config.yaml` to include PostgreSQL and Redis services:

```yaml .upsun/config.yaml theme={null}
services:
  database:
    type: postgresql:16
  redis:
    type: redis:8.0
```

This minimal configuration creates:

* A PostgreSQL 16 database for persistent workflow storage.
* A Redis 8.0 instance for caching and the job queue.

## Step 3: Configure n8n application

Update your n8n application configuration in `.upsun/config.yaml` to connect to PostgreSQL and use Redis:

```yaml title=".upsun/config.yaml" {5-11} theme={null}
applications:
  app-n8n:
    type: 'nodejs:22'
    #...
    relationships:
      database:
      redis:
    workers:
      worker:
        commands:
          start: "n8n worker --concurrency=${N8N_WORKER_CONCURRENCY:-1}"
```

Key configuration points:

* **`relationships`** link n8n to PostgreSQL (as `database`) and Redis as a job queue.
* **`workers`** handle background job processing—scale the concurrency setting as needed.
* n8n auto-detects PostgreSQL and Redis via [services variables](/docs/development/variables#service-environment-variables) Upsun injects.

## Step 4: Add `.environment` specific environment variables

```ini location=".environment" theme={null}
# Config PostgreSQL
export DB_TYPE=postgresdb
export DB_POSTGRESDB_HOST=${DATABASE_HOST}
export DB_POSTGRESDB_PORT=${DATABASE_PORT}
export DB_POSTGRESDB_DATABASE=${DATABASE_PATH}
export DB_POSTGRESDB_USER=${DATABASE_USERNAME}
export DB_POSTGRESDB_PASSWORD=${DATABASE_PASSWORD}

# Config Redis
export N8N_CACHE_ENABLED=true
export N8N_CACHE_BACKEND=redis
export N8N_CACHE_REDIS_HOST=${REDIS_HOST}
export N8N_CACHE_REDIS_PORT=${REDIS_PORT}
export N8N_CACHE_REDIS_PASSWORD=${REDIS_PASSWORD}
export N8N_CACHE_REDIS_TTL=3600 # default to 1h

# Queue on Redis
export QUEUE_BULL_REDIS_HOST=${REDIS_HOST}
export QUEUE_BULL_REDIS_PORT=${REDIS_PORT}
export QUEUE_BULL_REDIS_PASSWORD=${REDIS_PASSWORD}

export QUEUE_HEALTH_CHECK_ACTIVE=true
```

Once you've updated the configuration:

```bash {filename="Terminal"} theme={null}
git add .upsun/config.yaml
git commit -m "Add PostgreSQL and Redis services"
```

## Step 5: Migrate existing data

User accounts can't be migrated automatically. The `export:entities` / `import:entities` CLI commands are still
experimental and unreliable across different n8n versions — attempts may fail with migration timestamp mismatches.

<Warning>
  Before migrating, make sure that nobody updates existing Workflows or Credentials in the current instance during the migration —
  changes will not be automatically re-exported.
</Warning>

### Exporting n8n encryption key

N8n uses a default pre-generated TOKEN to store your data securely in your SQLite database.
To be able to export and re-import your workflows and credentials into the new built version of n8n, your need to export
and save this token on the project level, for environment inheritance.

```bash title="Terminal" theme={null}
upsun variable:create \
  --name=N8N_ENCRYPTION_KEY \
  --prefix=env \
  --env=main \
  --sensitive=true \
  --level=project \
  --value=$(upsun ssh -e main -- "cat /app/.n8n/config | jq -r .encryptionKey")
```

This will create a new environment variable named `N8N_ENCRYPTION_KEY` with the value of the encryption key used in
your current n8n production instance, and let all environments inherit it.

### Exporting existing workflows

If you already have workflows in SQLite, you need to export them:

```bash title="Terminal" theme={null}
upsun ssh -e main -- "mkdir -p /tmp/n8n-export && n8n export:workflow --all --output=/tmp/n8n-export/workflows.json"
upsun ssh -e main -- "cat /tmp/n8n-export/workflows.json" > workflows.json
```

This will create a new file named `workflows.json` in your local directory with all your workflows exported.
This file is encrypted with the same encryption key as your current n8n instance, so you can re-import it in the new
n8n instance without any issue.

### Exporting existing credentials

If you already have credentials in SQLite, you need to export them:

```bash title="Terminal" theme={null}
upsun ssh -e main -- "mkdir -p /tmp/n8n-export && n8n export:credentials --all --output=/tmp/n8n-export/credentials.json"
upsun ssh -e main -- "cat /tmp/n8n-export/credentials.json" > credentials.json
```

This will create a new file named `credentials.json` in your local directory with all your credentials exported.
This file is encrypted with the same encryption key as your current n8n instance, so you can re-import it in the new
n8n instance without any issue.

## Step 6: Deploy

When all previous steps are done, deploy your new n8n application:

```bash {filename="Terminal"} theme={null}
upsun push
```

During the deployment:

1. PostgreSQL and Redis services are automatically provisioned.
2. The main n8n application starts and connects to both services.
3. Worker processes are spawned to handle background jobs independently.
4. n8n automatically detects the database is empty and initializes its schema.
5. Existing workflows and credentials from your SQLite database need to be reimported.

## Step 7: Import Workflows and Credentials

To import your existing workflows and credentials into the new n8n staging instance, follow these steps:

```bash title="Terminal" theme={null}
upsun ssh -- "n8n import:workflow --input=/dev/stdin" < workflows.json
upsun ssh -- "n8n import:credentials --input=/dev/stdin" < credentials.json
```

When import is finished, you can then open the frontend to check that everything is working correctly
by using the following command line:

```bash title="Terminal" theme={null}
upsun environment:url --primary
```

## Step 8: Verify the setup

After deployment, verify that n8n is using PostgreSQL and Redis:

1. Check the main application logs:
   ```bash title="Terminal" theme={null}
   upsun logs app-n8n
   ```
   Look for messages confirming PostgreSQL and Redis initialization.

2. Check worker process logs:
   ```bash title="Terminal" theme={null}
   upsun logs worker
   ```
   Verify workers are listening for jobs:
   ```bash title="Terminal" theme={null}
   [INFO] Message Queue: Ready on queue "default"
   ```

3. Confirm the connection from the n8n UI by running a test workflow—execution history should load instantly and background jobs should process via workers.

4. In your Upsun console, verify all services and processes are running and healthy.

## Step 9: Update production environment

Before merging to production, make sure to create a backup of your production environment, in case you need to rollback:

```bash title="Terminal" theme={null}
upsun backup:create --environment=main
```

### Merge to production

Once you've verified everything is working correctly in staging, you can merge your changes to the production branch:

```bash title="Terminal" theme={null}
git checkout main
git merge add-postgresql-redis
upsun push
```

This will trigger a deployment to production with the new PostgreSQL and Redis configuration.

### Reimport workflows and credentials to production

You can redo what you did in staging to export the encryption key, workflows and credentials from the current production instance, and re-import them in the new production instance:

```bash title="Terminal" theme={null}
upsun ssh -- "n8n import:workflow --input=/dev/stdin" < workflows.json
upsun ssh -- "n8n import:credentials --input=/dev/stdin" < credentials.json
```

<Warning>
  After importing is finished and you checked that everything is working correctly,
  make sure to delete the `workflows.json` and `credentials.json` files from your local
  directory, as they contain sensitive data that should not be stored unencrypted.
</Warning>

## Step 10: Recreate N8N users

As the users are stored in the database, they will not be automatically migrated from the old n8n instance to the new one.
You will need to [recreate them manually](https://docs.n8n.io/user-management/manage-users/) in the n8n UI.

<img src="https://mintcdn.com/upsun-c9761871/QvVRIdphS5yjjp2e/images/posts/use-cases/n8n-upgrade-postgresql-redis/n8n-setup-form.png?fit=max&auto=format&n=QvVRIdphS5yjjp2e&q=85&s=c9ebe69c8f443be89baa6c131cd209c3" alt="Create first user" width="1742" height="1300" data-path="images/posts/use-cases/n8n-upgrade-postgresql-redis/n8n-setup-form.png" />

## Performance tuning tips

Now that you're using PostgreSQL and Redis with dedicated workers, optimize further:

### Worker concurrency

Adjust the `N8N_WORKER_CONCURRENCY` environment variable to control how many jobs a worker processes simultaneously:

```yaml .upsun/config.yaml {8} theme={null}
applications:
  app-n8n:
    type: 'nodejs:22'
    #...
    variables:
      env:
        #...
        N8N_WORKER_CONCURRENCY: "2"  # Default is 1
```

Higher concurrency handles more workflows in parallel, but requires more memory—that's why `container_profile: HIGHER_MEMORY` is recommended.

### PostgreSQL optimization

* **Backup regularly**: Enable automatic backups in your Upsun environment to protect your workflow data.
* **Monitor disk usage**: As your execution history grows, the database will expand. Allocate enough disk space or set retention policies.
* **Monitor slow queries**: Check PostgreSQL logs if workflow execution feels sluggish.

### Redis optimization

* **Monitor queue depth**: Use `upsun ssh` to check Redis memory and queue depth during peak times:

```bash title="Terminal" theme={null}
upsun ssh
redis-cli
> INFO stats
```

## Troubleshooting

### **Workers not processing jobs**

* Verify worker process logs: `upsun logs worker`
* Check Redis is running: `upsun logs redis`
* Ensure `N8N_WORKER_CONCURRENCY` is set to a reasonable value.

### **High memory usage**

* Confirm `container_profile: HIGHER_MEMORY` is set in your n8n app config.
* Lower `N8N_WORKER_CONCURRENCY` if workers exceed available memory.
* Monitor via: `upsun ssh` → `top` or check environment metrics in the console.

### **PostgreSQL connection errors**

* Check app logs: `upsun logs app`
* Ensure the relationship names match in both `applications` and services.
* Verify environment variables are correctly set and injected.

### **Workflows not appearing after migration**

* Verify credentials were correctly re-entered (they don't auto-migrate).
* Check that all imports completed successfully in the UI.
* Ensure `.n8n` mount has enough storage space.

## Next steps

You now have a production-ready n8n setup on Upsun. From here, you can:

* **Add more workflows** without performance concerns.
* **Enable API access** for external integrations.
* **Set up monitoring** with Upsun's observability tools.
* **Integrate with your CI/CD pipeline** for workflow deployment.

Want to share how you're using n8n on Upsun? Tweet us [@Upsun](https://twitter.com/upsun).

***

## Resources

* [n8n Documentation](https://docs.n8n.io/)
* [Upsun PostgreSQL Service](https://developer.upsun.com/docs/add-services/postgresql)
* [Upsun Redis Service](https://developer.upsun.com/docs/add-services/redis)
* [n8n on Upsun Tutorial](/posts/hands-on/nocode-n8n)
