Database Persistence & TypeORM
Relevant source files
The following files were used as context for generating this wiki page:
The n8n persistence layer manages how the application stores, retrieves, and updates records in durable storage. The system uses TypeORM as its Object-Relational Mapper (ORM) to support multiple database backends, primarily SQLite and PostgreSQL. This layer provides the necessary abstractions to maintain application state, workflow definitions, and execution history across restarts.
Architecture is structured around a strict boundary where database-specific logic stays within the persistence layer, while business logic interacts through domain-shaped repositories. This separation ensures that high-level services do not depend directly on the underlying database driver or ORM specifics.
Architecture and Persistence Layer Boundary
The persistence layer exists as a specialized module within the monorepo. TypeORM (@n8n/typeorm) is restricted to this layer to prevent database implementation details from leaking into business logic.
The TypeORM Boundary
Business logic, including services and controllers, must not import from @n8n/typeorm. Instead, they interact with the @n8n/db package. This package exposes repositories that return domain-shaped values rather than raw TypeORM entities.
- Repository Pattern: Use-case-named repository methods handle query construction. They accept plain parameters and return domain objects.
- No Generic Passthroughs: Repositories should not expose generic
find(options)methods that require TypeORM-specific objects likeFindOptionsWhereacross the boundary. - Exception Areas: Tests, migrations, and explicit helper-only adapters are the only areas exempt from this boundary.
Sources: AGENTS.md:209-224, packages/@n8n/db/AGENTS.md:5-13
Logical Data Flow
The following diagram illustrates the relationship between the Business Logic Layer and the Persistence Layer.
The diagram shows how Business Logic uses the TransactionRunner and Repository interfaces to interact with the database without directly touching TypeORM.
Sources: AGENTS.md:225-236, packages/@n8n/db/AGENTS.md:15-18
Transaction Management
n8n uses the TransactionRunner to orchestrate units of work that require atomicity. This primitive ensures that transactions are handled correctly within the persistence layer while being accessible to business logic.
Transaction Orchestration Rules
- Injection: Business logic injects the abstract
TransactionRunner. - Unit of Work: Work is wrapped in
txRunner.run(ctx, async (ctx) => ... ). - Operation Context: The callback receives an
OperationContext. This context must be passed into every repository method called within the transaction. - Context Joining: If a context already carries an active transaction, the
runmethod joins it rather than nesting a new one. - EntityManager Resolution: Repositories extend
BaseRepositoryand usethis.managerFor(ctx)to resolve the correctEntityManager.
Sources: AGENTS.md:225-236, packages/@n8n/db/AGENTS.md:15-18
Database Migrations
Migrations manage schema changes across different database types. n8n utilizes a Domain Specific Language (DSL) and a MigrationContext to ensure migrations are reversible and safe for production environments.
Migration Guidelines
- Scaffolding: Migrations are authored using the
n8n:db-migrationsskill for consistency. - Type Mapping: The DSL handles mapping types between SQLite and PostgreSQL.
- Review Process: The
@n8n-io/migrations-reviewteam enforces a pre-flight checklist for all schema changes. - Documentation: Database schema documentation is generated from migrations using
tbls.
Sources: packages/@n8n/db/AGENTS.md:20-27, CONTRIBUTING.md:167-183
Supported Databases and Configuration
n8n supports different database configurations depending on the environment and performance requirements.
| Database Type | Primary Use Case | Features |
|---|---|---|
| SQLite | Local development, simple setups | Default; file-based; no external setup required. |
| PostgreSQL | Production, multi-main setups | Supports concurrent access; required for high-volume environments. |
Configuration Options
Users can configure the database via environment variables or CLI flags during local development using the n8n-containers stack.
| Command | Description |
|---|---|
stack:sqlite | Runs a local instance using SQLite. |
stack:postgres | Spins up a PostgreSQL container for the instance. |
stack:multi-main | Runs a stack with a load balancer and shared database. |
Sources: AGENTS.md:144-149, CONTRIBUTING.md:310-335, packages/@n8n/workflow-sdk/src/prompts/best-practices/guides/data-persistence.ts:25-34
Persistence Patterns for Workflows
Workflows utilize different nodes and patterns to interact with the database. These interactions generally follow standard persistence lifecycle patterns.
Common Patterns
- Immediate Storage: Preserves raw data or form submissions as they arrive.
- Batch Storage: Aggregates multiple items before performing a single write operation to improve performance.
- Update/Upsert: Modifies existing records based on a unique identifier to maintain state.
- Lookup: Queries the database to enrich current workflow data with historical records.
Recommended Storage Nodes
- n8n Data Table: Built-in internal storage for small to medium datasets. No credentials required.
- External Databases: Nodes for MySQL and PostgreSQL for complex analytical queries or time-series data.
Sources: packages/@n8n/workflow-sdk/src/prompts/best-practices/guides/data-persistence.ts:60-100, packages/@n8n/workflow-sdk/src/prompts/best-practices/guides/data-analysis.ts:133-145
Testing and Data Integrity
The persistence layer is tested using both unit and E2E tests to ensure data remains consistent during operations.
- Database Resets: E2E tests often utilize
RESET_E2E_DB=trueto ensure a fresh state for sequential tests. - API Testing: API-driven tests verify that data created via endpoints (e.g.,
/rest/workflows) is correctly persisted in the database. - Encryption Boundary: Sensitive data like credentials must be encrypted via
cipher.encryptV2()before being stored in the database.
Sources: packages/quality/testing/playwright/CONTRIBUTING.md:10-25, packages/quality/testing/playwright/CONTRIBUTING.md:214-232, AGENTS.md:255-265
Summary
Database Persistence in n8n is built upon a strict separation between business logic and the TypeORM-driven persistence layer. By using the TransactionRunner and Repository patterns, the system achieves atomic operations and database independence. This architecture facilitates scaling from simple SQLite local files to complex, multi-instance PostgreSQL production environments while maintaining data integrity through a robust migration system and encryption boundary.