[{"_id":"/docs/self-hosting/environment-variables","structured":{"contents":[{"content":"This page documents NocoDB's environment variables, grouped by area: database, storage, authentication, caching, rate limiting, and more."},{"content":"For production deployments, set all environment variables marked as \"Mandatory\". They affect performance, security, and core functionality."},{"heading":"backward-compatibility","content":"NocoDB maintains full backward compatibility with legacy environment variable names. If you're using older variable names, they will continue to work. However, we recommend using the new naming convention for clarity and consistency. When multiple names are available, the system checks them in this priority order:"},{"heading":"backward-compatibility","content":"New recommended name (e.g., NC_RATE_LIMIT_DATA_API_DURATION)"},{"heading":"backward-compatibility","content":"Legacy name (e.g., NC_DATA_API_TTL)"},{"heading":"backward-compatibility","content":"Default value"},{"heading":"backward-compatibility","content":"This allows for gradual migration without breaking existing deployments."},{"heading":"database","content":"Variable"},{"heading":"database","content":"Mandatory"},{"heading":"database","content":"Description"},{"heading":"database","content":"If Not Set"},{"heading":"database","content":"NC_DB"},{"heading":"database","content":"Yes"},{"heading":"database","content":"The primary database where all NocoDB metadata and data are stored. Example format: pg://host.docker.internal:5432?u=username&p=password&d=database_name."},{"heading":"database","content":"A local SQLite database will be created in the root folder if NC_DB is not specified."},{"heading":"database","content":"NC_DB_JSON"},{"heading":"database","content":"No"},{"heading":"database","content":"Allows setting the database connection using a valid knex connection JSON string instead of NC_DB."},{"heading":"database","content":"NC_DB_JSON_FILE"},{"heading":"database","content":"No"},{"heading":"database","content":"A path to a knex connection JSON file can be used to specify the database connection, as an alternative to NC_DB."},{"heading":"database","content":"DATABASE_URL"},{"heading":"database","content":"No"},{"heading":"database","content":"A JDBC URL string can be used for the database connection instead of NC_DB."},{"heading":"database","content":"DATABASE_URL_FILE"},{"heading":"database","content":"No"},{"heading":"database","content":"A path to a file containing a JDBC URL can be specified for the database connection as an alternative to NC_DB."},{"heading":"database","content":"NC_CONNECTION_ENCRYPT_KEY"},{"heading":"database","content":"No"},{"heading":"database","content":"The key used to encrypt the credentials of external databases.  Warning: Changing this variable may break the application. If you must change it, use the CLI as described in the NocoDB Secret CLI documentation."},{"heading":"database","content":"Keep connection credentials as plain text in the database if not set."},{"heading":"database","content":"NC_DB_POOL_MAX"},{"heading":"database","content":"No"},{"heading":"database","content":"Maximum number of connections in the database connection pool. Controls how many concurrent database connections NocoDB can maintain."},{"heading":"database","content":"Defaults to 10."},{"heading":"authentication","content":"Variable"},{"heading":"authentication","content":"Mandatory"},{"heading":"authentication","content":"Description"},{"heading":"authentication","content":"If Not Set"},{"heading":"authentication","content":"NC_AUTH_JWT_SECRET"},{"heading":"authentication","content":"Yes"},{"heading":"authentication","content":"This JWT secret is utilized for generating authentication tokens."},{"heading":"authentication","content":"A random secret will be generated automatically."},{"heading":"authentication","content":"NC_JWT_EXPIRES_IN"},{"heading":"authentication","content":"No"},{"heading":"authentication","content":"Specifies the expiration time for JWT tokens."},{"heading":"authentication","content":"Defaults to 10h."},{"heading":"authentication","content":"NC_GOOGLE_CLIENT_ID"},{"heading":"authentication","content":"No"},{"heading":"authentication","content":"Google client ID required to activate Google authentication."},{"heading":"authentication","content":"NC_GOOGLE_CLIENT_SECRET"},{"heading":"authentication","content":"No"},{"heading":"authentication","content":"Google client secret required to activate Google authentication."},{"heading":"authentication","content":"NC_ADMIN_EMAIL"},{"heading":"authentication","content":"No"},{"heading":"authentication","content":"Super admin email address. This is useful in case you need to recover your username and password. See update requirements."},{"heading":"authentication","content":"An initial prompt for email and password is required when accessing the UI for the first time."},{"heading":"authentication","content":"NC_ADMIN_PASSWORD"},{"heading":"authentication","content":"No"},{"heading":"authentication","content":"Super admin password. Must be at least 8 characters long, including one uppercase letter, one number, and one special character from $&+,:;=?@#'.^*()%!_-\\\". This is useful for username and password recovery. See update requirements."},{"heading":"authentication","content":"NC_DISABLE_EMAIL_AUTH"},{"heading":"authentication","content":"No"},{"heading":"authentication","content":"Disables email and password-based authentication, intended for use when Google authentication variables are configured."},{"heading":"authentication","content":"NC_REFRESH_TOKEN_EXP_IN_DAYS"},{"heading":"authentication","content":"No"},{"heading":"authentication","content":"Specifies the expiration time for refresh tokens in days. Must be a positive number. (On-premise only)"},{"heading":"authentication","content":"Defaults to 30 days."},{"heading":"updating-super-admin-credentials","content":"To update either NC_ADMIN_EMAIL or NC_ADMIN_PASSWORD, you must set both variables together."},{"heading":"storage","content":"Variable"},{"heading":"storage","content":"Mandatory"},{"heading":"storage","content":"Description"},{"heading":"storage","content":"If Not Set"},{"heading":"storage","content":"Legacy Names (Still Supported)"},{"heading":"storage","content":"NC_S3_BUCKET_NAME"},{"heading":"storage","content":"No"},{"heading":"storage","content":"The name of the AWS S3 bucket used for the S3 storage plugin."},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_S3_REGION"},{"heading":"storage","content":"No"},{"heading":"storage","content":"The AWS S3 region where the S3 storage plugin bucket is located. Note that NC_S3_ENDPOINT takes precedence if set (the endpoint URL includes the region)."},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_S3_ENDPOINT"},{"heading":"storage","content":"No"},{"heading":"storage","content":"S3 endpoint for S3 storage plugin."},{"heading":"storage","content":"Defaults to s3.<region>.amazonaws.com"},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_S3_ACCESS_KEY"},{"heading":"storage","content":"No"},{"heading":"storage","content":"The AWS access key ID for the S3 storage plugin. Required if no role access in use."},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_S3_ACCESS_SECRET"},{"heading":"storage","content":"No"},{"heading":"storage","content":"The AWS access secret associated with the S3 storage plugin. Required if no role access in use."},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_S3_FORCE_PATH_STYLE"},{"heading":"storage","content":"No"},{"heading":"storage","content":"Whether to force path-style requests for the S3 storage plugin."},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_S3_ACL"},{"heading":"storage","content":"No"},{"heading":"storage","content":"The ACL for the objects in S3"},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_ATTACHMENT_FIELD_SIZE"},{"heading":"storage","content":"No"},{"heading":"storage","content":"Maximum file size allowed for attachments in bytes."},{"heading":"storage","content":"Defaults to 20971520 (20 MiB)."},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_FORM_FIELD_MAX_SIZE"},{"heading":"storage","content":"No"},{"heading":"storage","content":"Sets the maximum size in bytes for individual form fields during multipart uploads in shared form views. Useful for increasing limit for large text or JSON fields to prevent 'Field value too long' errors when form data is submitted by individuals outside your organization."},{"heading":"storage","content":"Defaults to 10485760 (10 MiB)."},{"heading":"storage","content":"NC_NON_ATTACHMENT_FIELD_SIZE"},{"heading":"storage","content":"NC_MAX_ATTACHMENTS_ALLOWED"},{"heading":"storage","content":"No"},{"heading":"storage","content":"Maximum number of attachments allowed per cell."},{"heading":"storage","content":"Defaults to 10."},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_ATTACHMENT_RETENTION_DAYS"},{"heading":"storage","content":"No"},{"heading":"storage","content":"Number of days to retain attachment on storage after all references deleted. (Set 0 to keep forever)"},{"heading":"storage","content":"Defaults to 10."},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_ATTACHMENT_ACCESS_CONTROL_ENABLED"},{"heading":"storage","content":"No"},{"heading":"storage","content":"Enables access control for attachments via pre-signed URLs. Set to true to activate; all other values are treated as false. ⚠ Note: Enabling this will make existing links inaccessible."},{"heading":"storage","content":"Defaults to false."},{"heading":"storage","content":"NC_SECURE_ATTACHMENTS"},{"heading":"storage","content":"NC_ATTACHMENT_EXPIRE_SECONDS"},{"heading":"storage","content":"No"},{"heading":"storage","content":"Time in seconds after which pre-signed URLs for attachments start to expire. The actual expiration will occur after this time plus an additional 10 minutes. Only applicable if NC_ATTACHMENT_ACCESS_CONTROL_ENABLED is enabled."},{"heading":"storage","content":"Defaults to 7200 (2 hours)."},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_THUMBNAIL_MAX_SIZE"},{"heading":"storage","content":"No"},{"heading":"storage","content":"Maximum size in bytes for image files that will generate thumbnails. Images larger than this size will not have thumbnails generated."},{"heading":"storage","content":"Defaults to 3145728 (3 MiB)."},{"heading":"storage","content":"-"},{"heading":"storage","content":"NC_DATA_IMPORT_FILE_SIZE"},{"heading":"storage","content":"No"},{"heading":"storage","content":"Maximum file size in bytes accepted by the data import upload endpoint (used when importing CSV / Excel / JSON files into a base)."},{"heading":"storage","content":"Defaults to 104857600 (100 MiB)."},{"heading":"storage","content":"-"},{"heading":"email-notifications","content":"The following SMTP variables are used to send email notifications to users, e.g., invites."},{"heading":"email-notifications","content":"Variable"},{"heading":"email-notifications","content":"Mandatory"},{"heading":"email-notifications","content":"Description"},{"heading":"email-notifications","content":"If Not Set"},{"heading":"email-notifications","content":"NC_SMTP_FROM"},{"heading":"email-notifications","content":"Yes"},{"heading":"email-notifications","content":"The email address used as the sender for the SMTP plugin."},{"heading":"email-notifications","content":"NC_SMTP_HOST"},{"heading":"email-notifications","content":"Yes"},{"heading":"email-notifications","content":"The hostname of the email server for the SMTP plugin."},{"heading":"email-notifications","content":"NC_SMTP_PORT"},{"heading":"email-notifications","content":"Yes"},{"heading":"email-notifications","content":"The network port of the email server for the SMTP plugin."},{"heading":"email-notifications","content":"NC_SMTP_USERNAME"},{"heading":"email-notifications","content":"Yes"},{"heading":"email-notifications","content":"The username for authentication with the SMTP plugin."},{"heading":"email-notifications","content":"NC_SMTP_PASSWORD"},{"heading":"email-notifications","content":"Yes"},{"heading":"email-notifications","content":"The password for authentication with the SMTP plugin."},{"heading":"email-notifications","content":"NC_SMTP_SECURE"},{"heading":"email-notifications","content":"No"},{"heading":"email-notifications","content":"Enables secure authentication for the SMTP plugin. Set to true to enable; all other values are considered false."},{"heading":"email-notifications","content":"Defaults to false."},{"heading":"email-notifications","content":"NC_SMTP_IGNORE_TLS"},{"heading":"email-notifications","content":"No"},{"heading":"email-notifications","content":"Ignores TLS for the SMTP plugin (disables STARTTLS even if SMTP servers support it). Set to true to ignore; all other values are considered false. Enabling this may compromise security. For more details, see Nodemailer's SMTP documentation."},{"heading":"email-notifications","content":"Defaults to false."},{"heading":"email-notifications","content":"NC_SMTP_REJECT_UNAUTHORIZED"},{"heading":"email-notifications","content":"No"},{"heading":"email-notifications","content":"Rejects connections to SMTP servers with invalid (self-signed) TLS certificates. Set to true to reject; all other values are considered false. Enabling this hardens security against man-in-the-middle attacks. For more details, see Nodemailer's SMTP documentation."},{"heading":"email-notifications","content":"Defaults to false."},{"heading":"backend","content":"Variable"},{"heading":"backend","content":"Mandatory"},{"heading":"backend","content":"Description"},{"heading":"backend","content":"If Not Set"},{"heading":"backend","content":"PORT"},{"heading":"backend","content":"No"},{"heading":"backend","content":"Specifies the network port on which NocoDB will run."},{"heading":"backend","content":"Defaults to 8080."},{"heading":"backend","content":"NODE_OPTIONS"},{"heading":"backend","content":"No"},{"heading":"backend","content":"Node.js options to pass to the instance."},{"heading":"frontend","content":"Variable"},{"heading":"frontend","content":"Mandatory"},{"heading":"frontend","content":"Description"},{"heading":"frontend","content":"If Not Set"},{"heading":"frontend","content":"Legacy Names (Still Supported)"},{"heading":"frontend","content":"NC_SITE_URL"},{"heading":"frontend","content":"Yes *"},{"heading":"frontend","content":"Required for outbound emails to work. Invitation and password-reset emails build their links from this URL, so if it is unset those links point to the wrong host. Also used for the Swagger docs URL and other backend URL construction. Set it to your public-facing NocoDB URL, for example https://nocodb.example.com."},{"heading":"frontend","content":"By default, it infers the URL from the incoming request on the backend. If the server is behind a proxy, this may result in incorrect URLs."},{"heading":"frontend","content":"NC_PUBLIC_URL"},{"heading":"frontend","content":"NC_DASHBOARD_URL"},{"heading":"frontend","content":"No"},{"heading":"frontend","content":"Defines a custom dashboard URL path."},{"heading":"frontend","content":"Defaults to /dashboard."},{"heading":"frontend","content":"NUXT_PUBLIC_NC_BACKEND_URL"},{"heading":"frontend","content":"No"},{"heading":"frontend","content":"Specifies a custom backend URL."},{"heading":"frontend","content":"Defaults to http://localhost:8080."},{"heading":"cache","content":"Variable"},{"heading":"cache","content":"Mandatory"},{"heading":"cache","content":"Description"},{"heading":"cache","content":"If Not Set"},{"heading":"cache","content":"Legacy Names (Still Supported)"},{"heading":"cache","content":"NC_CACHE_REDIS_URL"},{"heading":"cache","content":"Yes"},{"heading":"cache","content":"Specifies the Redis URL used for caching.  Eg: redis://:authpassword@127.0.0.1:6380/4"},{"heading":"cache","content":"Caching layer of backend"},{"heading":"cache","content":"NC_REDIS_URL"},{"heading":"cache","content":"NC_JOBS_REDIS_URL"},{"heading":"cache","content":"No"},{"heading":"cache","content":"Separate Redis URL for job queue. Falls back to NC_REDIS_JOB_URL. Useful for isolating job queue workload from cache operations. (On-premise only)"},{"heading":"cache","content":"Required if using job queue features."},{"heading":"cache","content":"NC_REDIS_JOB_URL"},{"heading":"cache","content":"NC_RATE_LIMIT_REDIS_URL"},{"heading":"cache","content":"No"},{"heading":"cache","content":"Separate Redis URL for rate limiting. Falls back to NC_THROTTLER_REDIS. Useful for isolating rate limiting operations from cache and jobs. (On-premise only)"},{"heading":"cache","content":"Uses in-memory rate limiting."},{"heading":"cache","content":"NC_THROTTLER_REDIS"},{"heading":"rate-limiting","content":"(On-premise only) NocoDB implements rate limiting for different API types to prevent abuse and ensure fair usage. Each API type has three configurable parameters: DURATION (time window in milliseconds), MAX_REQUESTS (max requests in that window), and BLOCK_DURATION (how long to block in milliseconds after exceeding limits)."},{"heading":"rest-api-with-auth-token","content":"Rate limits for authenticated API requests using auth tokens."},{"heading":"rest-api-with-auth-token","content":"Variable"},{"heading":"rest-api-with-auth-token","content":"Mandatory"},{"heading":"rest-api-with-auth-token","content":"Description"},{"heading":"rest-api-with-auth-token","content":"If Not Set"},{"heading":"rest-api-with-auth-token","content":"Legacy Names (Still Supported)"},{"heading":"rest-api-with-auth-token","content":"NC_RATE_LIMIT_DATA_API_DURATION"},{"heading":"rest-api-with-auth-token","content":"No"},{"heading":"rest-api-with-auth-token","content":"Time window in milliseconds for data API rate limiting."},{"heading":"rest-api-with-auth-token","content":"Defaults to 1000 (1s)."},{"heading":"rest-api-with-auth-token","content":"NC_DATA_API_TTL"},{"heading":"rest-api-with-auth-token","content":"NC_RATE_LIMIT_DATA_API_MAX_REQUESTS"},{"heading":"rest-api-with-auth-token","content":"No"},{"heading":"rest-api-with-auth-token","content":"Maximum number of data API requests allowed per duration window."},{"heading":"rest-api-with-auth-token","content":"Defaults to 5."},{"heading":"rest-api-with-auth-token","content":"NC_DATA_COUNT"},{"heading":"rest-api-with-auth-token","content":"NC_RATE_LIMIT_DATA_API_BLOCK_DURATION"},{"heading":"rest-api-with-auth-token","content":"No"},{"heading":"rest-api-with-auth-token","content":"Duration in milliseconds to block requests after exceeding the limit."},{"heading":"rest-api-with-auth-token","content":"Defaults to 30000 (30s)."},{"heading":"rest-api-with-auth-token","content":"NC_DATA_BLOCK_DURATION"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"Rate limits for metadata operations (base, table, field management) using auth tokens."},{"heading":"rest-api-with-auth-token-metadata-operations","content":"Variable"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"Mandatory"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"Description"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"If Not Set"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"Legacy Names (Still Supported)"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"NC_RATE_LIMIT_META_API_DURATION"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"No"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"Time window in milliseconds for meta API rate limiting."},{"heading":"rest-api-with-auth-token-metadata-operations","content":"Defaults to 60000 (60s)."},{"heading":"rest-api-with-auth-token-metadata-operations","content":"NC_META_API_TTL"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"NC_RATE_LIMIT_META_API_MAX_REQUESTS"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"No"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"Maximum number of meta API requests allowed per duration window."},{"heading":"rest-api-with-auth-token-metadata-operations","content":"Defaults to 60."},{"heading":"rest-api-with-auth-token-metadata-operations","content":"NC_META_COUNT"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"NC_RATE_LIMIT_META_API_BLOCK_DURATION"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"No"},{"heading":"rest-api-with-auth-token-metadata-operations","content":"Duration in milliseconds to block requests after exceeding the limit."},{"heading":"rest-api-with-auth-token-metadata-operations","content":"Defaults to 30000 (30s)."},{"heading":"rest-api-with-auth-token-metadata-operations","content":"NC_META_BLOCK_DURATION"},{"heading":"web-ui---data-operations","content":"Rate limits for data operations performed through the web interface (browser sessions)."},{"heading":"web-ui---data-operations","content":"Variable"},{"heading":"web-ui---data-operations","content":"Mandatory"},{"heading":"web-ui---data-operations","content":"Description"},{"heading":"web-ui---data-operations","content":"If Not Set"},{"heading":"web-ui---data-operations","content":"Legacy Names (Still Supported)"},{"heading":"web-ui---data-operations","content":"NC_RATE_LIMIT_DATA_GUI_DURATION"},{"heading":"web-ui---data-operations","content":"No"},{"heading":"web-ui---data-operations","content":"Time window in milliseconds for web UI data operations rate limiting."},{"heading":"web-ui---data-operations","content":"Defaults to 1000 (1s)."},{"heading":"web-ui---data-operations","content":"NC_DATA_GUI_API_TTL"},{"heading":"web-ui---data-operations","content":"NC_RATE_LIMIT_DATA_GUI_MAX_REQUESTS"},{"heading":"web-ui---data-operations","content":"No"},{"heading":"web-ui---data-operations","content":"Maximum number of web UI data requests allowed per duration window."},{"heading":"web-ui---data-operations","content":"Defaults to 30000."},{"heading":"web-ui---data-operations","content":"NC_DATA_GUI_COUNT"},{"heading":"web-ui---data-operations","content":"NC_RATE_LIMIT_DATA_GUI_BLOCK_DURATION"},{"heading":"web-ui---data-operations","content":"No"},{"heading":"web-ui---data-operations","content":"Duration in milliseconds to block requests after exceeding the limit."},{"heading":"web-ui---data-operations","content":"Defaults to 0 (no block)."},{"heading":"web-ui---data-operations","content":"NC_DATA_GUI_BLOCK_DURATION"},{"heading":"web-ui---metadata-operations","content":"Rate limits for metadata operations (base, table, field management) performed through the web interface (browser sessions)."},{"heading":"web-ui---metadata-operations","content":"Variable"},{"heading":"web-ui---metadata-operations","content":"Mandatory"},{"heading":"web-ui---metadata-operations","content":"Description"},{"heading":"web-ui---metadata-operations","content":"If Not Set"},{"heading":"web-ui---metadata-operations","content":"Legacy Names (Still Supported)"},{"heading":"web-ui---metadata-operations","content":"NC_RATE_LIMIT_META_GUI_DURATION"},{"heading":"web-ui---metadata-operations","content":"No"},{"heading":"web-ui---metadata-operations","content":"Time window in milliseconds for web UI metadata operations rate limiting."},{"heading":"web-ui---metadata-operations","content":"Defaults to 1000 (1s)."},{"heading":"web-ui---metadata-operations","content":"NC_META_GUI_API_TTL"},{"heading":"web-ui---metadata-operations","content":"NC_RATE_LIMIT_META_GUI_MAX_REQUESTS"},{"heading":"web-ui---metadata-operations","content":"No"},{"heading":"web-ui---metadata-operations","content":"Maximum number of web UI metadata requests allowed per duration window."},{"heading":"web-ui---metadata-operations","content":"Defaults to 1000."},{"heading":"web-ui---metadata-operations","content":"NC_META_GUI_COUNT"},{"heading":"web-ui---metadata-operations","content":"NC_RATE_LIMIT_META_GUI_BLOCK_DURATION"},{"heading":"web-ui---metadata-operations","content":"No"},{"heading":"web-ui---metadata-operations","content":"Duration in milliseconds to block requests after exceeding the limit."},{"heading":"web-ui---metadata-operations","content":"Defaults to 0 (no block)."},{"heading":"web-ui---metadata-operations","content":"NC_META_GUI_BLOCK_DURATION"},{"heading":"shared-views--forms-public-access","content":"Rate limits for publicly accessible shared views and forms (no authentication required)."},{"heading":"shared-views--forms-public-access","content":"Variable"},{"heading":"shared-views--forms-public-access","content":"Mandatory"},{"heading":"shared-views--forms-public-access","content":"Description"},{"heading":"shared-views--forms-public-access","content":"If Not Set"},{"heading":"shared-views--forms-public-access","content":"Legacy Names (Still Supported)"},{"heading":"shared-views--forms-public-access","content":"NC_RATE_LIMIT_PUBLIC_API_DURATION"},{"heading":"shared-views--forms-public-access","content":"No"},{"heading":"shared-views--forms-public-access","content":"Time window in milliseconds for public API rate limiting."},{"heading":"shared-views--forms-public-access","content":"Defaults to 1000 (1s)."},{"heading":"shared-views--forms-public-access","content":"NC_PUBLIC_API_TTL"},{"heading":"shared-views--forms-public-access","content":"NC_RATE_LIMIT_PUBLIC_API_MAX_REQUESTS"},{"heading":"shared-views--forms-public-access","content":"No"},{"heading":"shared-views--forms-public-access","content":"Maximum number of public API requests allowed per duration window."},{"heading":"shared-views--forms-public-access","content":"Defaults to 10."},{"heading":"shared-views--forms-public-access","content":"NC_PUBLIC_COUNT"},{"heading":"shared-views--forms-public-access","content":"NC_RATE_LIMIT_PUBLIC_API_BLOCK_DURATION"},{"heading":"shared-views--forms-public-access","content":"No"},{"heading":"shared-views--forms-public-access","content":"Duration in milliseconds to block requests after exceeding the limit."},{"heading":"shared-views--forms-public-access","content":"Defaults to 0 (no block)."},{"heading":"shared-views--forms-public-access","content":"NC_PUBLIC_BLOCK_DURATION"},{"heading":"product-configuration","content":"Variable"},{"heading":"product-configuration","content":"Mandatory"},{"heading":"product-configuration","content":"Description"},{"heading":"product-configuration","content":"If Not Set"},{"heading":"product-configuration","content":"Legacy Names (Still Supported)"},{"heading":"product-configuration","content":"NC_DB_QUERY_LIMIT_DEFAULT"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Default pagination limit for data tables."},{"heading":"product-configuration","content":"Defaults to 25. Maximum is 100"},{"heading":"product-configuration","content":"DB_QUERY_LIMIT_DEFAULT"},{"heading":"product-configuration","content":"NC_DB_QUERY_LIMIT_GROUP_BY_GROUP"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Number of groups per page."},{"heading":"product-configuration","content":"Defaults to 10."},{"heading":"product-configuration","content":"DB_QUERY_LIMIT_GROUP_BY_GROUP"},{"heading":"product-configuration","content":"NC_DB_QUERY_LIMIT_GROUP_BY_RECORD"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Number of records per group."},{"heading":"product-configuration","content":"Defaults to 10."},{"heading":"product-configuration","content":"DB_QUERY_LIMIT_GROUP_BY_RECORD"},{"heading":"product-configuration","content":"NC_DB_QUERY_LIMIT_MAX"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Maximum allowable pagination limit."},{"heading":"product-configuration","content":"Defaults to 1000."},{"heading":"product-configuration","content":"DB_QUERY_LIMIT_MAX"},{"heading":"product-configuration","content":"NC_DB_QUERY_LIMIT_MIN"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Minimum allowable pagination limit."},{"heading":"product-configuration","content":"Defaults to 10"},{"heading":"product-configuration","content":"DB_QUERY_LIMIT_MIN"},{"heading":"product-configuration","content":"NC_CONNECT_TO_EXTERNAL_DB_DISABLED"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Disables the ability to create bases on external databases."},{"heading":"product-configuration","content":"-"},{"heading":"product-configuration","content":"NC_INVITE_ONLY_SIGNUP"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Disables public signup; signup is possible only via invitations. Integrated into the super admin settings menu as of version 0.99.0."},{"heading":"product-configuration","content":"-"},{"heading":"product-configuration","content":"NC_REQUEST_BODY_SIZE"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Maximum bytes allowed in the request body, based on ExpressJS limits."},{"heading":"product-configuration","content":"Defaults to 1048576 (1 MB)."},{"heading":"product-configuration","content":"-"},{"heading":"product-configuration","content":"NC_WEBHOOK_ALLOW_PRIVATE_NETWORK"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Allows webhooks to call private network addresses (localhost, RFC1918 ranges). Set to true to enable; all other values are considered false. ⚠ Security risk."},{"heading":"product-configuration","content":"Defaults to false."},{"heading":"product-configuration","content":"NC_ALLOW_LOCAL_HOOKS"},{"heading":"product-configuration","content":"NC_ALLOW_LOCAL_EXTERNAL_DBS"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Allows connections to external databases on local network addresses, posing potential security risks. Set to true to enable; all other values are considered false."},{"heading":"product-configuration","content":"Defaults to false."},{"heading":"product-configuration","content":"-"},{"heading":"product-configuration","content":"NC_DATABASE_COLUMN_NAME_SANITIZE_ENABLED"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Enables sanitization of column names during creation to prevent SQL injection. Set to false to disable sanitization."},{"heading":"product-configuration","content":"Defaults to true (enabled)."},{"heading":"product-configuration","content":"NC_SANITIZE_COLUMN_NAME"},{"heading":"product-configuration","content":"NC_APP_DATA_DIR"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Specifies the directory to store metadata and app-related files. In Docker setups, this maps to /usr/app/data/ for mounting volumes."},{"heading":"product-configuration","content":"Defaults to the current working directory."},{"heading":"product-configuration","content":"NC_TOOL_DIR"},{"heading":"product-configuration","content":"NC_DISABLE_PG_DATA_REFLECTION"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Disables the creation of a schema for each base in Postgres.  Click here for more detail"},{"heading":"product-configuration","content":"Defaults to false."},{"heading":"product-configuration","content":"-"},{"heading":"product-configuration","content":"NC_MIGRATIONS_DISABLED"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Disables NocoDB migrations."},{"heading":"product-configuration","content":"-"},{"heading":"product-configuration","content":"NC_DISABLE_AUDIT"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Disables the audit log feature."},{"heading":"product-configuration","content":"Defaults to false."},{"heading":"product-configuration","content":"-"},{"heading":"product-configuration","content":"NC_WEBHOOK_LOG_LEVEL"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Configures logging levels for webhook execution. Possible values: OFF, ERROR, ALL. More details can be found under Webhooks."},{"heading":"product-configuration","content":"Defaults to OFF."},{"heading":"product-configuration","content":"NC_AUTOMATION_LOG_LEVEL"},{"heading":"product-configuration","content":"NC_IFRAME_ALLOWED_DOMAINS"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Comma-separated list of domains allowed to be embedded in iframes. (On-premise only) Example: *.nocodb.com,*.mycompany.com"},{"heading":"product-configuration","content":"NC_IFRAME_WHITELIST_DOMAINS"},{"heading":"product-configuration","content":"NC_API_BULK_OPERATION_MAX_RECORDS"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Maximum number of records that can be inserted/updated/deleted in a single v3 API request. Helps prevent memory issues with large bulk operations. (On-premise only)"},{"heading":"product-configuration","content":"Defaults to 10 for v3 APIs."},{"heading":"product-configuration","content":"NC_DATA_PAYLOAD_LIMIT"},{"heading":"product-configuration","content":"NC_WORKER_MODE_ENABLED"},{"heading":"product-configuration","content":"No"},{"heading":"product-configuration","content":"Set to true to designate this instance as a background job processor. When enabled, this instance will only process jobs and not serve HTTP requests. (On-premise only)"},{"heading":"product-configuration","content":"Defaults to false."},{"heading":"product-configuration","content":"NC_WORKER_CONTAINER"},{"heading":"postgres-data-reflection","content":"The NocoDB UI mirrors your Postgres database schema. Same tables, same columns. This is done by creating a schema for each base in Postgres. The feature is enabled by default if the user has the required permissions. To disable it, set the NC_DISABLE_PG_DATA_REFLECTION environment variable to true."},{"heading":"e2b-script-execution","content":"E2B provides sandboxed cloud environments for executing scripts. These variables are required to enable the Webhook Run Script and Workflow Run Script node features."},{"heading":"e2b-script-execution","content":"Variable"},{"heading":"e2b-script-execution","content":"Mandatory"},{"heading":"e2b-script-execution","content":"Description"},{"heading":"e2b-script-execution","content":"If Not Set"},{"heading":"e2b-script-execution","content":"E2B_API_KEY"},{"heading":"e2b-script-execution","content":"No"},{"heading":"e2b-script-execution","content":"API key for authenticating with the E2B service. Required to enable script execution features."},{"heading":"e2b-script-execution","content":"Script execution features are disabled."},{"heading":"e2b-script-execution","content":"E2B_TEMPLATE_ID"},{"heading":"e2b-script-execution","content":"No"},{"heading":"e2b-script-execution","content":"The E2B sandbox template ID that defines the execution environment for scripts. Set to yah8ggzfy44fpdop51ai."},{"heading":"e2b-script-execution","content":"Script execution features are disabled."},{"heading":"logging--monitoring","content":"Variable"},{"heading":"logging--monitoring","content":"Mandatory"},{"heading":"logging--monitoring","content":"Description"},{"heading":"logging--monitoring","content":"If Not Set"},{"heading":"logging--monitoring","content":"NC_SENTRY_DSN"},{"heading":"logging--monitoring","content":"No"},{"heading":"logging--monitoring","content":"Data Source Name (DSN) for integrating with Sentry for monitoring and error tracking."},{"heading":"logging--monitoring","content":"NC_DISABLE_ERR_REPORTS"},{"heading":"logging--monitoring","content":"No"},{"heading":"logging--monitoring","content":"Disable default Sentry error reporting."},{"heading":"logging--monitoring","content":"TRUE"},{"heading":"debugging-only","content":"Variable"},{"heading":"debugging-only","content":"Mandatory"},{"heading":"debugging-only","content":"Description"},{"heading":"debugging-only","content":"If Not Set"},{"heading":"debugging-only","content":"DEBUG"},{"heading":"debugging-only","content":"No"},{"heading":"debugging-only","content":"Allows to enable various levels of debug logging. Set to nc:* to enable all NocoDB debug logging. Set to nc:*,knex:* to additionally enable database query logging. Recommended only during debugging."},{"heading":"debugging-only","content":"Unset by default."},{"heading":"debugging-only","content":"NC_ENABLE_ALL_API_ERROR_LOGGING"},{"heading":"debugging-only","content":"No"},{"heading":"debugging-only","content":"Enables more verbose API error logging. Recommended only during debugging."},{"heading":"debugging-only","content":"Defaults to false."},{"heading":"debugging-only","content":"NC_DISABLE_CACHE"},{"heading":"debugging-only","content":"No"},{"heading":"debugging-only","content":"Disables caching to force metadata fetching directly from the database instead of Redis/cache. Recommended only during debugging."},{"heading":"debugging-only","content":"Defaults to false."},{"heading":"telemetry","content":"Variable"},{"heading":"telemetry","content":"Mandatory"},{"heading":"telemetry","content":"Description"},{"heading":"telemetry","content":"If Not Set"},{"heading":"telemetry","content":"NC_DISABLE_TELE"},{"heading":"telemetry","content":"No"},{"heading":"telemetry","content":"Disables the telemetry to prevent sending anonymous usage data. Please keep it enabled to help us understand the usage of the product and the impact that any new breaking change can cause."},{"heading":"support-chat","content":"Variable"},{"heading":"support-chat","content":"Mandatory"},{"heading":"support-chat","content":"Description"},{"heading":"support-chat","content":"If Not Set"},{"heading":"support-chat","content":"NC_DISABLE_SUPPORT_CHAT"},{"heading":"support-chat","content":"No"},{"heading":"support-chat","content":"Disables the support chat within the product. We use Chatwoot which is an open source support system."},{"heading":"support-chat","content":"FALSE"},{"heading":"litestream","content":"Litestream is used only when NC_DB is set to SQLite. It backs up the SQLite database and stores it in S3."},{"heading":"litestream","content":"Variable"},{"heading":"litestream","content":"Mandatory"},{"heading":"litestream","content":"Description"},{"heading":"litestream","content":"If Not Set"},{"heading":"litestream","content":"LITESTREAM_S3_ENDPOINT"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"URL of an S3-compatible object storage service endpoint for Litestream replication of NocoDB's default SQLite database. Example: s3.eu-central-1.amazonaws.com."},{"heading":"litestream","content":"Defaults to AWS S3."},{"heading":"litestream","content":"LITESTREAM_S3_REGION"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"AWS region of the Litestream replication object storage bucket. Note that LITESTREAM_S3_ENDPOINT takes precedence if configured (the endpoint URL includes the region)."},{"heading":"litestream","content":"Defaults to the default region configured in AWS."},{"heading":"litestream","content":"LITESTREAM_S3_BUCKET"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Name of the object storage bucket to store the Litestream replication in."},{"heading":"litestream","content":"Litestream replication is disabled if this variable is not set."},{"heading":"litestream","content":"LITESTREAM_S3_PATH"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Directory path to use within the Litestream replication object storage bucket."},{"heading":"litestream","content":"Defaults to nocodb."},{"heading":"litestream","content":"LITESTREAM_S3_ACCESS_KEY_ID"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Authentication key ID for the Litestream replication object storage bucket."},{"heading":"litestream","content":"Litestream replication is disabled if this variable is not set."},{"heading":"litestream","content":"LITESTREAM_S3_SECRET_ACCESS_KEY"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Authentication secret for the Litestream replication object storage bucket."},{"heading":"litestream","content":"Litestream replication is disabled if this variable is not set."},{"heading":"litestream","content":"LITESTREAM_S3_SKIP_VERIFY"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Whether to disable TLS verification for the Litestream replication object storage service. Useful when testing against a local node such as MinIO and you are using self-signed certificates."},{"heading":"litestream","content":"Defaults to false."},{"heading":"litestream","content":"LITESTREAM_RETENTION"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Amount of time Litestream snapshot and WAL files are kept. After the retention period, a new snapshot is created and the old one is removed. WAL files that exist before the oldest snapshot will also be removed."},{"heading":"litestream","content":"Defaults to 1440h (60 days)."},{"heading":"litestream","content":"LITESTREAM_RETENTION_CHECK_INTERVAL"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Frequency in which Litestream will check if retention needs to be enforced."},{"heading":"litestream","content":"Defaults to 72h (3 days)."},{"heading":"litestream","content":"LITESTREAM_SNAPSHOT_INTERVAL"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Frequency in which new Litestream snapshots are created. A higher frequency reduces the time to restore since newer snapshots will have fewer WAL frames to apply. Retention still applies to these snapshots."},{"heading":"litestream","content":"Defaults to 24h (1 day)."},{"heading":"litestream","content":"LITESTREAM_SYNC_INTERVAL"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Frequency in which frames are pushed to the Litestream replica. Increasing this frequency can increase object storage costs significantly."},{"heading":"litestream","content":"Defaults to 60s (1 minute)."},{"heading":"litestream","content":"LITESTREAM_AGE_PUBLIC_KEY"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"age public key generated by age-keygen (age1...) or SSH public key (ssh-ed25519 AAAA..., ssh-rsa AAAA...) used to encrypt the Litestream replication for. Refer to the relevant Litestream documentation for details."},{"heading":"litestream","content":"Litestream replication is unencrypted if this variable is not set."},{"heading":"litestream","content":"LITESTREAM_AGE_SECRET_KEY"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"age secret key (AGE-SECRET-KEY-1...) used to encrypt the Litestream replication with. Refer to the relevant Litestream documentation for details."},{"heading":"litestream","content":"Litestream replication is unencrypted if this variable is not set."},{"heading":"litestream","content":"AWS_ACCESS_KEY_ID"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Deprecated. Please use LITESTREAM_S3_ACCESS_KEY_ID instead."},{"heading":"litestream","content":"AWS_SECRET_ACCESS_KEY"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Deprecated. Please use LITESTREAM_S3_SECRET_ACCESS_KEY instead."},{"heading":"litestream","content":"AWS_BUCKET"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Deprecated. Please use LITESTREAM_S3_BUCKET instead."},{"heading":"litestream","content":"AWS_BUCKET_PATH"},{"heading":"litestream","content":"No"},{"heading":"litestream","content":"Deprecated. Please use LITESTREAM_S3_PATH instead."}],"headings":[{"id":"backward-compatibility","content":"Backward compatibility"},{"id":"database","content":"Database"},{"id":"authentication","content":"Authentication"},{"id":"updating-super-admin-credentials","content":"Updating super admin credentials"},{"id":"storage","content":"Storage"},{"id":"email-notifications","content":"Email notifications"},{"id":"backend","content":"Backend"},{"id":"frontend","content":"Frontend"},{"id":"cache","content":"Cache"},{"id":"rate-limiting","content":"Rate limiting"},{"id":"rest-api-with-auth-token","content":"REST API with auth token"},{"id":"rest-api-with-auth-token-metadata-operations","content":"REST API with auth token (metadata operations)"},{"id":"web-ui---data-operations","content":"Web UI - data operations"},{"id":"web-ui---metadata-operations","content":"Web UI - metadata operations"},{"id":"shared-views--forms-public-access","content":"Shared views & forms (public access)"},{"id":"product-configuration","content":"Product configuration"},{"id":"postgres-data-reflection","content":"Postgres data reflection"},{"id":"e2b-script-execution","content":"E2B (script execution)"},{"id":"logging--monitoring","content":"Logging & monitoring"},{"id":"debugging-only","content":"Debugging only"},{"id":"telemetry","content":"Telemetry"},{"id":"support-chat","content":"Support chat"},{"id":"litestream","content":"Litestream"}]},"url":"/docs/self-hosting/environment-variables","title":"Environment variables","description":"Configure your self-hosted NocoDB instance: database, storage, authentication, caching, rate limiting, and more."},{"_id":"/docs/self-hosting","structured":{"contents":[{"content":"Self-hosting NocoDB means running it on your own server or computer instead of NocoDB Cloud. You stay in control of your data and your upgrade cadence."},{"heading":"pick-your-path","content":"If you want to..."},{"heading":"pick-your-path","content":"Start here"},{"heading":"pick-your-path","content":"Try NocoDB locally in 60 seconds"},{"heading":"pick-your-path","content":"Quickstart"},{"heading":"pick-your-path","content":"Deploy on a single server with HTTPS"},{"heading":"pick-your-path","content":"Single-server install"},{"heading":"pick-your-path","content":"Run with managed Postgres, custom SSL, or your own infrastructure"},{"heading":"pick-your-path","content":"Custom infrastructure"},{"heading":"pick-your-path","content":"Use a platform-specific guide (Homebrew, Cloudron, AWS, GCP, DO…)"},{"heading":"pick-your-path","content":"Community methods"},{"heading":"requirements","content":"Minimum"},{"heading":"requirements","content":"Recommended (production)"},{"heading":"requirements","content":"CPU"},{"heading":"requirements","content":"2 vCPU"},{"heading":"requirements","content":"4 vCPU"},{"heading":"requirements","content":"RAM"},{"heading":"requirements","content":"2 GB"},{"heading":"requirements","content":"8 GB"},{"heading":"requirements","content":"Disk"},{"heading":"requirements","content":"10 GB"},{"heading":"requirements","content":"50 GB+"},{"heading":"requirements","content":"The Single-server install runs on Linux, macOS, or Windows; a Linux server is recommended for production. The Quickstart works on any platform with Docker Desktop."},{"heading":"licensing","content":"NocoDB Community is distributed under the Fair Code Sustainable Use License. You may self-host NocoDB and use it for internal purposes, including building applications for your own organization. Offering NocoDB as a hosted or managed service to third parties may require a commercial license. See the official license text or Fair Code license details for the full terms."},{"heading":"licensing","content":"For Business, Scale, or Enterprise plans (SSO, audit logs, row-level security, priority support, airgapped deployment), see Purchase a license and License activation."}],"headings":[{"id":"pick-your-path","content":"Pick your path"},{"id":"requirements","content":"Requirements"},{"id":"licensing","content":"Licensing"}]},"url":"/docs/self-hosting","title":"Self-hosting","description":"Run NocoDB on your infrastructure with full control over your data."},{"_id":"/docs/self-hosting/license-activation","structured":{"contents":[{"content":"Self-hosted NocoDB requires a valid license key to enable paid features. The right activation method depends on whether your server has internet access. If you do not have a license yet, see Purchase a License."},{"content":"type: warn"},{"content":"type: info"},{"content":"Same image, license-gated. nocodb/nocodb:latest ships with both Community and Enterprise code. Enterprise features activate when a valid license key is set, either via the Admin Panel or the NC_LICENSE_KEY env var. There is no separate nocodb-ee image to pull."},{"heading":"which-method-should-i-use","content":"Method"},{"heading":"which-method-should-i-use","content":"When to use"},{"heading":"which-method-should-i-use","content":"Internet needed"},{"heading":"which-method-should-i-use","content":"Standard"},{"heading":"which-method-should-i-use","content":"Your server can reach the internet"},{"heading":"which-method-should-i-use","content":"Yes, ongoing"},{"heading":"which-method-should-i-use","content":"Airgapped"},{"heading":"which-method-should-i-use","content":"Your server has limited or no internet access"},{"heading":"which-method-should-i-use","content":"One-time only"},{"heading":"which-method-should-i-use","content":"Offline (manual)"},{"heading":"which-method-should-i-use","content":"Your server has no internet access at all"},{"heading":"which-method-should-i-use","content":"Never"},{"heading":"which-method-should-i-use","content":"Most self-hosted customers use Standard. If your environment restricts outbound connections, use Airgapped. If your server can never connect to the internet, reach out and we will set it up for you."},{"heading":"which-method-should-i-use","content":"type: info"},{"heading":"standard-license","content":"Best for cloud VMs, typical data centers, and any environment with internet access."},{"heading":"how-to-activate","content":"Open the NocoDB UI and go to Admin Panel > License."},{"heading":"how-to-activate","content":"Paste your license key into the Enter your license key field. The Save button activates once a key is entered."},{"heading":"how-to-activate","content":"Click Save. NocoDB validates the key against NocoDB Cloud. On success, the status banner turns green and paid features are activated immediately. No restart needed."},{"heading":"how-it-stays-active","content":"NocoDB checks in with the license server every 6 hours. The call is small and carries no application data. If a check-in fails, NocoDB retries every hour. After 48 hours without a successful check-in, paid features are paused. They resume automatically once connectivity is restored."},{"heading":"network-requirements","content":"NocoDB makes outbound HTTPS calls to a single endpoint:"},{"heading":"network-requirements","content":"If your network filters outbound traffic by host or path, allow exactly that host (app.nocodb.com) and that path (/api/v1/on-premise/agent) over TCP 443. Nothing else is involved."},{"heading":"network-requirements","content":"To point at a private license server, set:"},{"heading":"setting-the-license-key-via-environment-variable","content":"Instead of pasting the key in the Admin Panel, set it at startup:"},{"heading":"setting-the-license-key-via-environment-variable","content":"When NC_LICENSE_KEY is set in the environment, the Admin Panel → License page becomes read-only. The environment value wins. Useful for IaC and ephemeral instances that should reactivate on every boot."},{"heading":"multi-process-deployments","content":"If you run the API and worker as separate containers, or scale nocodb to multiple replicas, license-state changes need to propagate across processes. NocoDB does this via a Redis pub/sub channel. A working Redis connection (NC_REDIS_URL) is required for license changes made in the Admin Panel to take effect across all processes without restarts. The production examples and the Single-server install already include Redis."},{"heading":"airgapped-license","content":"type: warn"},{"heading":"airgapped-license","content":"Best for firewalled or restricted networks, or anywhere ongoing internet access is not possible."},{"heading":"airgapped-license","content":"With an airgapped license, NocoDB connects to the internet once during setup. After that single activation, it runs fully offline for the lifetime of the license. No check-ins, no callbacks."},{"heading":"how-to-activate-1","content":"You will receive a license key starting with nc_ag_ from NocoDB."},{"heading":"how-to-activate-1","content":"Make sure your server has temporary outbound internet access (just for the initial activation)."},{"heading":"how-to-activate-1","content":"Open the NocoDB UI and go to Admin Panel > License."},{"heading":"how-to-activate-1","content":"Paste your nc_ag_ license key and click Save."},{"heading":"how-to-activate-1","content":"NocoDB activates the license with a single outbound call. Once confirmed, you can remove internet access. NocoDB keeps running with full paid features."},{"heading":"notes","content":"After activation, no internet connection is needed until the license expires."},{"heading":"notes","content":"The license is tied to your installation. If your Instance ID changes, contact us to re-activate."},{"heading":"offline-activation","content":"type: warn"},{"heading":"offline-activation","content":"For environments that can never connect to the internet: classified networks, isolated infrastructure, or strict compliance setups."},{"heading":"offline-activation","content":"We handle this for you:"},{"heading":"offline-activation","content":"Start NocoDB. During startup, it prints an Instance ID in the logs:"},{"heading":"offline-activation","content":"You will see something like:"},{"heading":"offline-activation","content":"Send us your Instance ID along with your license key by emailing cs@nocodb.com."},{"heading":"offline-activation","content":"We will send you back a license token. Open the NocoDB UI, go to Admin Panel > License, paste the token, and click Save."},{"heading":"offline-activation","content":"type: info"},{"heading":"manage-license-on-this-instance","content":"Once a license is active, the Admin Panel → License page exposes additional controls."},{"heading":"refresh-license","content":"Click Refresh License to re-validate the license against NocoDB Cloud. Use this if your plan was recently upgraded or renewed and the instance has not yet picked up the change."},{"heading":"remove-license","content":"Click Remove License to deactivate the license on this instance. You will be asked to confirm. After removal, the instance reverts to NocoDB Community and paid features are disabled. The license key remains available in your NocoDB Cloud account and can be re-applied at any time."},{"heading":"manage-license-billing-portal","content":"Once a license is active, a Manage License card appears on the License page. Click it to open the Stripe billing portal. See Manage billing for what you can do there."},{"heading":"what-is-the-instance-id","content":"The Instance ID uniquely identifies your NocoDB deployment. It is printed in the server logs every time NocoDB starts and stays stable across restarts and updates. If it ever changes, reach out for a new activation."},{"heading":"renewing-your-license","content":"Method"},{"heading":"renewing-your-license","content":"What to do"},{"heading":"renewing-your-license","content":"Standard"},{"heading":"renewing-your-license","content":"Nothing. Renewal is automatic once your subscription is renewed."},{"heading":"renewing-your-license","content":"Airgapped"},{"heading":"renewing-your-license","content":"Temporarily restore internet access and restart NocoDB. The new expiry is picked up automatically."},{"heading":"renewing-your-license","content":"Offline"},{"heading":"renewing-your-license","content":"Contact us for a new license token and update it in Admin Panel > License."},{"heading":"troubleshooting","content":"Problem"},{"heading":"troubleshooting","content":"What to do"},{"heading":"troubleshooting","content":"Activation fails"},{"heading":"troubleshooting","content":"Make sure your server can reach https://app.nocodb.com/api/v1/on-premise/agent over TCP 443. Check firewalls, egress proxies, and DNS."},{"heading":"troubleshooting","content":"\"Bound to a different installation\""},{"heading":"troubleshooting","content":"Your installation environment changed. Contact us at cs@nocodb.com for a re-issue."},{"heading":"troubleshooting","content":"Paid features stopped working"},{"heading":"troubleshooting","content":"For standard licenses, restore internet access and restart. For expired licenses, renew your subscription."},{"heading":"troubleshooting","content":"Can't find the Instance ID"},{"heading":"troubleshooting","content":"Check the NocoDB container logs. The Instance ID is printed during startup."}],"headings":[{"id":"which-method-should-i-use","content":"Which method should I use?"},{"id":"standard-license","content":"Standard license"},{"id":"how-to-activate","content":"How to activate"},{"id":"how-it-stays-active","content":"How it stays active"},{"id":"network-requirements","content":"Network requirements"},{"id":"setting-the-license-key-via-environment-variable","content":"Setting the license key via environment variable"},{"id":"multi-process-deployments","content":"Multi-process deployments"},{"id":"airgapped-license","content":"Airgapped license"},{"id":"how-to-activate-1","content":"How to activate"},{"id":"notes","content":"Notes"},{"id":"offline-activation","content":"Offline activation"},{"id":"manage-license-on-this-instance","content":"Manage license on this instance"},{"id":"refresh-license","content":"Refresh license"},{"id":"remove-license","content":"Remove license"},{"id":"manage-license-billing-portal","content":"Manage license (billing portal)"},{"id":"what-is-the-instance-id","content":"What is the Instance ID?"},{"id":"renewing-your-license","content":"Renewing your license"},{"id":"troubleshooting","content":"Troubleshooting"}]},"url":"/docs/self-hosting/license-activation","title":"Activating a license","description":"Activate your NocoDB self-hosted license. Standard, airgapped, and fully offline methods."},{"_id":"/docs/self-hosting/purchase-license","structured":{"contents":[{"content":"NocoDB offers self-serve licensing for self-hosted deployments. Business and Scale plan licenses can be purchased directly through your NocoDB Cloud account and activated on your instance by pasting the license key. No manual provisioning or sales engagement required. Enterprise plans are tailored to your organization's requirements and provisioned by the NocoDB Sales team."},{"content":"type: warn"},{"heading":"prerequisites","content":"A self-hosted NocoDB instance running on Postgres."},{"heading":"prerequisites","content":"A NocoDB Cloud account for purchasing and managing licenses."},{"heading":"1-navigate-to-self-hosted-licenses","content":"Log in to your NocoDB Cloud account. Click your avatar in the bottom-left corner and select Account Settings."},{"heading":"1-navigate-to-self-hosted-licenses","content":"From the account settings sidebar, open Self-Hosted Licenses. If you have no licenses yet, you will see the empty state:"},{"heading":"1-navigate-to-self-hosted-licenses","content":"Click Buy Your First License to proceed to plan selection. If you already have licenses, click Buy New License from the list view."},{"heading":"2-select-a-plan","content":"Choose your billing period and plan."},{"heading":"2-select-a-plan","content":"Billing period. Toggle between Monthly and Annually. Annual billing is offered at a discount."},{"heading":"2-select-a-plan","content":"Business. Self-serve plan billed per editor, starting at 1 seat. Includes SSO, table- and field-level permissions, teams, external-app sync, and single-provider AI. Click Select Business to proceed to checkout."},{"heading":"2-select-a-plan","content":"Scale. Self-serve plan for growing teams, billed per editor with a 3-seat minimum. Everything in Business plus unlimited workspaces, audit logs, row-level security, team hierarchy, and multi-provider AI. Click Select Scale to proceed to checkout."},{"heading":"2-select-a-plan","content":"Enterprise. Tailored to your organization. Everything in Scale plus SCIM, airgapped installation, a staging environment, priority support, and invoice-based payments. Click Contact Sales to get in touch with the NocoDB team."},{"heading":"2-select-a-plan","content":"For both self-serve plans, editor (and above) seats added to your instance after activation are billed automatically based on your actual usage."},{"heading":"3-complete-payment","content":"A Stripe embedded checkout form will appear. Enter your payment details and click Subscribe."},{"heading":"4-copy-your-license-key","content":"After successful payment, your license key is displayed on the confirmation screen."},{"heading":"4-copy-your-license-key","content":"Click Copy License Key to copy it to your clipboard. You can also view all your licenses and retrieve the key later from the Self-Hosted Licenses list."},{"heading":"4-copy-your-license-key","content":"Once you have the key, follow License Activation to activate it on your instance."},{"heading":"manage-billing","content":"The Stripe billing portal is available from two places:"},{"heading":"manage-billing","content":"From your instance. Once a license is active, the second card on the Admin Panel → License page changes to Manage License. Click it to open the billing portal."},{"heading":"manage-billing","content":"From NocoDB Cloud. Go to Account → Self-Hosted Licenses → Manage Billing."},{"heading":"manage-billing","content":"The billing portal lets you:"},{"heading":"manage-billing","content":"View current subscriptions and next billing dates"},{"heading":"manage-billing","content":"Update or add payment methods"},{"heading":"manage-billing","content":"Update billing information"},{"heading":"manage-billing","content":"View invoice history"},{"heading":"manage-billing","content":"Cancel a subscription"}],"headings":[{"id":"prerequisites","content":"Prerequisites"},{"id":"purchasing-a-license","content":"Purchasing a license"},{"id":"1-navigate-to-self-hosted-licenses","content":"1. Navigate to Self-Hosted Licenses"},{"id":"2-select-a-plan","content":"2. Select a plan"},{"id":"3-complete-payment","content":"3. Complete payment"},{"id":"4-copy-your-license-key","content":"4. Copy your license key"},{"id":"manage-billing","content":"Manage billing"}]},"url":"/docs/self-hosting/purchase-license","title":"Purchasing a license","description":"Purchase a Business or Scale plan license for your self-hosted NocoDB instance through NocoDB Cloud."},{"_id":"/docs/self-hosting/troubleshooting","structured":{"contents":[{"content":"Most self-hosting problems surface in the container logs and come down to a handful of causes: a port conflict, a database connection, a proxy or URL mismatch, or SSL. Start with the logs, then jump to the matching section below."},{"heading":"start-with-the-logs","content":"NocoDB prints its configuration and any fatal error on startup. docker compose ps shows whether a container is restarting (a crash loop) or stuck in an unhealthy state."},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"Symptom in logs"},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"Likely cause"},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"Fix"},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"ECONNREFUSED or could not connect to ... 5432"},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"Postgres not reachable"},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"Confirm the db container is healthy, or that your external NC_DB host, port, and credentials are correct."},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"password authentication failed"},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"Wrong database credentials"},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"Fix the password in docker.env or nocodb/db.json, then docker compose up -d."},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"requires PostgreSQL"},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"Running a license on SQLite or MySQL"},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"License activation needs Postgres. See License activation."},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"Exits immediately, no clear error"},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"Corrupt or version-mismatched data volume"},{"heading":"nocodb-wont-start-or-keeps-restarting","content":"Check you didn't point a newer Postgres major version at an older data volume. See Backups."},{"heading":"a-port-is-already-in-use","content":"With a domain, NocoDB runs behind Traefik on ports 80 and 443; local mode uses 8080."},{"heading":"a-port-is-already-in-use","content":"Stop the conflicting service, or run NocoDB in local mode (leave the domain blank) behind your existing reverse proxy. See Bringing your own reverse proxy or SSL."},{"heading":"links-redirects-or-oauth-callbacks-point-to-the-wrong-url","content":"If NocoDB generates http://localhost:8080 links, or login redirects break behind a proxy, the instance doesn't know its public URL."},{"heading":"links-redirects-or-oauth-callbacks-point-to-the-wrong-url","content":"Set NC_SITE_URL to your public-facing URL, for example https://nocodb.example.com."},{"heading":"links-redirects-or-oauth-callbacks-point-to-the-wrong-url","content":"If you terminate TLS at a proxy, forward the X-Forwarded-Proto and Host headers so NocoDB builds https:// links correctly."},{"heading":"links-redirects-or-oauth-callbacks-point-to-the-wrong-url","content":"See Frontend environment variables."},{"heading":"ssl-certificate-isnt-issued-lets-encrypt","content":"Traefik can't obtain a certificate. Check, in order:"},{"heading":"ssl-certificate-isnt-issued-lets-encrypt","content":"Your domain's DNS A record points at the server's public IP."},{"heading":"ssl-certificate-isnt-issued-lets-encrypt","content":"Port 80 is open to the internet (Let's Encrypt validates over HTTP)."},{"heading":"ssl-certificate-isnt-issued-lets-encrypt","content":"You used a real hostname, not an IP address (certificates can't be issued for bare IPs)."},{"heading":"ssl-certificate-isnt-issued-lets-encrypt","content":"Run docker compose logs traefik and read the ACME error."},{"heading":"attachments-dont-load-or-upload","content":"Local storage: confirm the nocodb_data volume is mounted and the disk isn't full (df -h)."},{"heading":"attachments-dont-load-or-upload","content":"Broken links after enabling access control: turning on NC_ATTACHMENT_ACCESS_CONTROL_ENABLED switches to expiring pre-signed URLs, which makes previously shared public links stop working. See Storage environment variables."},{"heading":"attachments-dont-load-or-upload","content":"S3 or MinIO: verify your NC_S3_* credentials, bucket, and region."},{"heading":"data-looks-empty-after-an-upgrade","content":"Almost always the bind-mount to named-volume switch: the new compose file mounted fresh, empty volumes. Your data is still in the old ./postgres and ./nocodb directories. Follow Migrating from bind mounts to named volumes."},{"heading":"locked-out-or-need-to-reset-the-super-admin","content":"Set both variables together (NocoDB requires both to change either), then restart:"},{"heading":"locked-out-or-need-to-reset-the-super-admin","content":"See Updating super admin credentials."},{"heading":"a-license-wont-activate","content":"See the License activation troubleshooting table. It covers activation failures, instance-ID changes, and paused features."},{"heading":"still-stuck","content":"Capture logs to share: docker compose logs --no-color > nocodb-logs.txt"},{"heading":"still-stuck","content":"Open an issue on GitHub, or reach the community on Discord."}],"headings":[{"id":"start-with-the-logs","content":"Start with the logs"},{"id":"nocodb-wont-start-or-keeps-restarting","content":"NocoDB won't start or keeps restarting"},{"id":"a-port-is-already-in-use","content":"A port is already in use"},{"id":"links-redirects-or-oauth-callbacks-point-to-the-wrong-url","content":"Links, redirects, or OAuth callbacks point to the wrong URL"},{"id":"ssl-certificate-isnt-issued-lets-encrypt","content":"SSL certificate isn't issued (Let's Encrypt)"},{"id":"attachments-dont-load-or-upload","content":"Attachments don't load or upload"},{"id":"data-looks-empty-after-an-upgrade","content":"Data looks empty after an upgrade"},{"id":"locked-out-or-need-to-reset-the-super-admin","content":"Locked out or need to reset the super admin"},{"id":"a-license-wont-activate","content":"A license won't activate"},{"id":"still-stuck","content":"Still stuck?"}]},"url":"/docs/self-hosting/troubleshooting","title":"Troubleshooting","description":"Diagnose and fix common self-hosted NocoDB issues: startup, networking, SSL, database, attachments, and login."},{"_id":"/docs/self-hosting/installation/community-methods","structured":{"contents":[{"content":"type: warn"},{"content":"Not maintained by the NocoDB team. These methods are provided by platform vendors or the community. For first-class self-hosting, use Quickstart, Single-server, or Custom infrastructure."},{"heading":"homebrew","content":"For local development on macOS or Linux:"},{"heading":"homebrew","content":"NocoDB starts on http://localhost:8080. Default storage is SQLite. For any real use beyond a quick look, use Quickstart instead, which sets up Postgres."},{"heading":"cloudron","content":"NocoDB is available in the Cloudron App Store. Install it from your Cloudron dashboard: search for \"NocoDB\" in the App Store and click Install. Cloudron handles backups, SSL, and updates for you."},{"heading":"caprover","content":"Available as a one-click app. From your CapRover dashboard, go to Apps → One-Click Apps/Databases, search for NocoDB, and deploy."},{"heading":"railway","content":"Use the NocoDB Railway template: search Templates for \"NocoDB\". Railway provisions Postgres and runs NocoDB automatically."},{"heading":"digitalocean-app-platform","content":"From the DigitalOcean dashboard, click Create → Apps."},{"heading":"digitalocean-app-platform","content":"Choose Docker Hub as source and set the image to nocodb/nocodb."},{"heading":"digitalocean-app-platform","content":"Configure environment variables for your database connection."},{"heading":"digitalocean-app-platform","content":"Launch the app. NocoDB will be reachable at https://your-app-name.ondigitalocean.app/."},{"heading":"digitalocean-app-platform","content":"For a production setup with Postgres, also create a DigitalOcean Managed Database and wire its connection string into NC_DB_JSON_FILE (mount the file as a config) or use NC_DB."},{"heading":"aws-ecs-fargate","content":"NocoDB runs on Fargate. The minimal task definition:"},{"heading":"aws-ecs-fargate","content":"Use an Application Load Balancer to terminate TLS and forward to port 8080. Connect to RDS Postgres for the database."},{"heading":"gcp-cloud-run","content":"Cloud Run requires images to live in GCR or Artifact Registry, hence the pull, tag, and push above. Configure environment variables for your Postgres (Cloud SQL works well) via --set-env-vars."},{"heading":"sealos--elestio--repocloud","content":"Each platform has a one-click NocoDB template:"},{"heading":"sealos--elestio--repocloud","content":"Deploy on Sealos"},{"heading":"sealos--elestio--repocloud","content":"Deploy on Elestio"},{"heading":"sealos--elestio--repocloud","content":"Deploy on RepoCloud"},{"heading":"nix--nixos","content":"type: warn"},{"heading":"nix--nixos","content":"The NixOS module is not maintained since NocoDB v0.264.6 (September 2025). The information below remains for reference but is not actively tested against current NocoDB releases."},{"heading":"freebsd--freenas--truenas-jail","content":"See this community gist by C. R. Zamana for jail-based installation on FreeBSD-derived systems."}],"headings":[{"id":"homebrew","content":"Homebrew"},{"id":"cloudron","content":"Cloudron"},{"id":"caprover","content":"CapRover"},{"id":"railway","content":"Railway"},{"id":"digitalocean-app-platform","content":"DigitalOcean App Platform"},{"id":"aws-ecs-fargate","content":"AWS ECS (Fargate)"},{"id":"gcp-cloud-run","content":"GCP Cloud Run"},{"id":"sealos--elestio--repocloud","content":"Sealos / Elestio / RepoCloud"},{"id":"nix--nixos","content":"Nix / NixOS"},{"id":"freebsd--freenas--truenas-jail","content":"FreeBSD / FreeNAS / TrueNAS Jail"}]},"url":"/docs/self-hosting/installation/community-methods","title":"Community methods","description":"Platform-specific install paths maintained by the community or platform vendors."},{"_id":"/docs/self-hosting/installation/custom-infrastructure","structured":{"contents":[{"content":"For deployments that don't fit the single-server installation wizard: managed databases, custom SSL certificates, private CAs, your own reverse proxy, multi-replica setups, or Kubernetes."},{"content":"type: info"},{"heading":"when-to-use-this-page","content":"You're using a managed Postgres (RDS, Azure, Cloud SQL) with public CA SSL."},{"heading":"when-to-use-this-page","content":"You're using a self-managed Postgres with a private/internal CA."},{"heading":"when-to-use-this-page","content":"You already have a TLS certificate and want to pin it via Traefik."},{"heading":"when-to-use-this-page","content":"You have nginx, Caddy, or a load balancer in front and want NocoDB on port 8080."},{"heading":"when-to-use-this-page","content":"You're deploying to Kubernetes and want a reference compose to translate."},{"heading":"option-a-clone-the-repo-and-run-the-wizard-interactively","content":"setup.sh runs the same installation wizard as the Single-server install one-liner, writing its output into the current working directory. Use this when you want to edit the generated files before bringing the stack up."},{"heading":"option-b-copy-a-pre-built-example","content":"The docker-compose/examples/ directory ships a set of curated configurations."},{"heading":"option-b-copy-a-pre-built-example","content":"Example"},{"heading":"option-b-copy-a-pre-built-example","content":"Postgres"},{"heading":"option-b-copy-a-pre-built-example","content":"Redis"},{"heading":"option-b-copy-a-pre-built-example","content":"Proxy"},{"heading":"option-b-copy-a-pre-built-example","content":"Best for"},{"heading":"option-b-copy-a-pre-built-example","content":"quickstart-demo"},{"heading":"option-b-copy-a-pre-built-example","content":"Bundled"},{"heading":"option-b-copy-a-pre-built-example","content":"Bundled"},{"heading":"option-b-copy-a-pre-built-example","content":"None (port 8080)"},{"heading":"option-b-copy-a-pre-built-example","content":"Local eval / \"show me NocoDB\""},{"heading":"option-b-copy-a-pre-built-example","content":"managed-postgres"},{"heading":"option-b-copy-a-pre-built-example","content":"External managed (RDS/Azure/Cloud SQL)"},{"heading":"option-b-copy-a-pre-built-example","content":"External"},{"heading":"option-b-copy-a-pre-built-example","content":"None (port 8080)"},{"heading":"option-b-copy-a-pre-built-example","content":"Production behind your own LB"},{"heading":"option-b-copy-a-pre-built-example","content":"external-postgres-and-redis"},{"heading":"option-b-copy-a-pre-built-example","content":"External self-managed"},{"heading":"option-b-copy-a-pre-built-example","content":"External"},{"heading":"option-b-copy-a-pre-built-example","content":"None (port 8080)"},{"heading":"option-b-copy-a-pre-built-example","content":"Minimal Docker footprint"},{"heading":"option-b-copy-a-pre-built-example","content":"traefik-custom-ssl"},{"heading":"option-b-copy-a-pre-built-example","content":"External managed"},{"heading":"option-b-copy-a-pre-built-example","content":"External"},{"heading":"option-b-copy-a-pre-built-example","content":"Traefik + custom TLS cert"},{"heading":"option-b-copy-a-pre-built-example","content":"Production with your own SSL cert"},{"heading":"option-b-copy-a-pre-built-example","content":"postgres-private-ca"},{"heading":"option-b-copy-a-pre-built-example","content":"External (private CA)"},{"heading":"option-b-copy-a-pre-built-example","content":"External"},{"heading":"option-b-copy-a-pre-built-example","content":"Traefik + Let's Encrypt"},{"heading":"option-b-copy-a-pre-built-example","content":"On-prem / private cloud DB"},{"heading":"option-b-copy-a-pre-built-example","content":"Quick start with an example:"},{"heading":"configuring-ssl-for-an-external-postgres-with-a-private-ca","content":"This is the most involved external-database setup. NocoDB reads its database connection from nocodb/db.json (knex format), which lets you embed a CA certificate inline:"},{"heading":"configuring-ssl-for-an-external-postgres-with-a-private-ca","content":"The CA must be a single string with newlines escaped as \\n. The postgres-private-ca example shows the full layout including a Traefik proxy."},{"heading":"configuring-ssl-for-an-external-postgres-with-a-private-ca","content":"To convert a multi-line PEM into the single-line JSON form:"},{"heading":"multi-replica--scaling","content":"NocoDB scales horizontally when Redis is configured (it's required for distributed coordination):"},{"heading":"multi-replica--scaling","content":"For more than a few replicas, run NocoDB in Kubernetes. Translate one of the examples into a Deployment + Service + Ingress, and point the same env vars at managed Postgres and Redis."},{"heading":"bringing-your-own-reverse-proxy","content":"The managed-postgres and external-postgres-and-redis examples expose NocoDB on host port 8080 with no Traefik. Put your own nginx, Caddy, or load balancer in front and forward HTTP traffic to that port. Forward the X-Forwarded-Proto and Host headers so NocoDB generates correct callback URLs."}],"headings":[{"id":"when-to-use-this-page","content":"When to use this page"},{"id":"option-a-clone-the-repo-and-run-the-wizard-interactively","content":"Option A: Clone the repo and run the wizard interactively"},{"id":"option-b-copy-a-pre-built-example","content":"Option B: Copy a pre-built example"},{"id":"configuring-ssl-for-an-external-postgres-with-a-private-ca","content":"Configuring SSL for an external Postgres with a private CA"},{"id":"multi-replica--scaling","content":"Multi-replica / scaling"},{"id":"bringing-your-own-reverse-proxy","content":"Bringing your own reverse proxy"}]},"url":"/docs/self-hosting/installation/custom-infrastructure","title":"Custom infrastructure","description":"Run NocoDB with managed databases, external Redis, custom SSL, private CAs, or your own reverse proxy."},{"_id":"/docs/self-hosting/installation/quickstart","structured":{"contents":[{"content":"The fastest way to try NocoDB locally. One command downloads the installer, generates a Compose stack (NocoDB, a worker, Postgres, and Redis), and starts it on http://localhost:8080. Works on Mac, Windows, and Linux."},{"content":"type: info"},{"content":"Prerequisite: Docker Desktop (Mac/Windows) or Docker Engine (Linux). Install it from docker.com before running the command below."},{"heading":"1-run","content":"This writes a ready-to-run stack into nocodb/ and brings it up. The first run pulls the images, so it can take a few minutes."},{"heading":"2-open-nocodb","content":"Visit http://localhost:8080. Sign up with an email and password. The first user becomes super admin."},{"heading":"what-this-runs","content":"Container"},{"heading":"what-this-runs","content":"Image"},{"heading":"what-this-runs","content":"Purpose"},{"heading":"what-this-runs","content":"nocodb"},{"heading":"what-this-runs","content":"nocodb/nocodb:latest"},{"heading":"what-this-runs","content":"The web app and API"},{"heading":"what-this-runs","content":"worker"},{"heading":"what-this-runs","content":"nocodb/nocodb:latest"},{"heading":"what-this-runs","content":"Background jobs (imports, exports, automations)"},{"heading":"what-this-runs","content":"db"},{"heading":"what-this-runs","content":"PostgreSQL"},{"heading":"what-this-runs","content":"Stores metadata and your data"},{"heading":"what-this-runs","content":"redis"},{"heading":"what-this-runs","content":"Redis"},{"heading":"what-this-runs","content":"Caching and job queue"},{"heading":"what-this-runs","content":"Data is stored in Docker-managed named volumes (postgres_data, redis_data, nocodb_data), so it persists across restarts and docker compose down. List them with docker volume ls."},{"heading":"common-operations","content":"The installer writes everything into nocodb/. Run these from there:"},{"heading":"prefer-not-to-run-a-script","content":"Grab the same four-container stack from the quickstart-demo example on GitHub: a plain Compose file you can read before running. Copy its docker-compose.yml into an empty directory, then start it:"},{"heading":"prefer-not-to-run-a-script","content":"It's the identical stack, just without the installer. Run the operations above from that directory."},{"heading":"next-steps","content":"Deploying to a server? See Single-server install. Same single command, plus automatic Traefik + Let's Encrypt SSL."},{"heading":"next-steps","content":"Need managed Postgres, custom SSL, or your own infrastructure? See Custom infrastructure for example configurations."},{"heading":"next-steps","content":"Want enterprise features? Purchase a license, then activate it."},{"heading":"next-steps","content":"Something not working? See Troubleshooting for startup, networking, SSL, and attachment issues."}],"headings":[{"id":"1-run","content":"1. Run"},{"id":"2-open-nocodb","content":"2. Open NocoDB"},{"id":"what-this-runs","content":"What this runs"},{"id":"common-operations","content":"Common operations"},{"id":"prefer-not-to-run-a-script","content":"Prefer not to run a script?"},{"id":"next-steps","content":"Next steps"}]},"url":"/docs/self-hosting/installation/quickstart","title":"Quickstart","description":"Run NocoDB locally in 60 seconds on Mac, Windows, or Linux."},{"_id":"/docs/self-hosting/installation/single-server","structured":{"contents":[{"content":"A single command runs NocoDB with Postgres + Redis, sets up Traefik with automatic Let's Encrypt SSL, and gives you a working HTTPS endpoint."},{"content":"Everything runs on one server: app, database, cache, and proxy. For a managed database, multiple app replicas, or Kubernetes, see Custom infrastructure."},{"content":"type: info"},{"content":"Prerequisites: Docker with the Compose v2 plugin, on a host with ports 80 and 443 reachable. A Linux server is recommended for production; macOS and Windows (Git Bash or WSL) work too. If using a real domain, point its DNS A record at this host's public IP before running the installer."},{"content":"type: info"},{"content":"Just evaluating locally? The Quickstart is the simpler path on Mac or Windows. This installer runs there too, but its HTTPS setup assumes a host reachable at your domain on ports 80 and 443."},{"heading":"2-answer-34-prompts","content":"Prompt"},{"heading":"2-answer-34-prompts","content":"What to enter"},{"heading":"2-answer-34-prompts","content":"Notes"},{"heading":"2-answer-34-prompts","content":"Domain"},{"heading":"2-answer-34-prompts","content":"nocodb.example.com"},{"heading":"2-answer-34-prompts","content":"Must resolve to this server. Blank or localhost gives local mode (port 8080); a bare IP serves plaintext HTTP on port 80. Both skip SSL."},{"heading":"2-answer-34-prompts","content":"Postgres"},{"heading":"2-answer-34-prompts","content":"1 (Bundled) or 2 (Existing)"},{"heading":"2-answer-34-prompts","content":"Bundled is the typical choice. Choose Existing to use a managed database (RDS, Cloud SQL, etc.)."},{"heading":"2-answer-34-prompts","content":"Redis"},{"heading":"2-answer-34-prompts","content":"1 (Bundled) or 2 (Existing)"},{"heading":"2-answer-34-prompts","content":"Same idea."},{"heading":"2-answer-34-prompts","content":"Let's Encrypt email"},{"heading":"2-answer-34-prompts","content":"ops@example.com"},{"heading":"2-answer-34-prompts","content":"Only asked when you provided a real domain. Used for SSL certificate renewal notifications."},{"heading":"2-answer-34-prompts","content":"After you confirm the summary, the installer writes everything into nocodb/, pulls the images, and starts the stack. The first run can take a few minutes."},{"heading":"3-open-nocodb","content":"Visit https://your-domain. Sign up with an email and password. The first user becomes super admin."},{"heading":"what-the-script-generates","content":"Postgres, Redis, and NocoDB application data (including attachments) are stored in Docker-managed named volumes, not in this directory. Run docker volume ls to see them. They survive docker compose down."},{"heading":"reviewing-the-script-before-running","content":"If you'd rather inspect what runs before piping it to bash:"},{"heading":"reviewing-the-script-before-running","content":"The script source lives in the nocodb/nocodb GitHub repo."},{"heading":"non-interactive-install","content":"For automation (CI, IaC, configuration management):"},{"heading":"non-interactive-install","content":"Full flag list:"},{"heading":"non-interactive-install","content":"Flag"},{"heading":"non-interactive-install","content":"Values"},{"heading":"non-interactive-install","content":"Notes"},{"heading":"non-interactive-install","content":"--quick"},{"heading":"non-interactive-install","content":"Bundled Postgres + Redis, local mode (port 8080). Add --domain= for production HTTPS."},{"heading":"non-interactive-install","content":"--domain="},{"heading":"non-interactive-install","content":"hostname or IP"},{"heading":"non-interactive-install","content":"Blank or localhost → local mode (port 8080). A bare IP serves plaintext HTTP on port 80 (no SSL)."},{"heading":"non-interactive-install","content":"--acme-email="},{"heading":"non-interactive-install","content":"email"},{"heading":"non-interactive-install","content":"Required for production with a valid domain."},{"heading":"non-interactive-install","content":"--image-tag="},{"heading":"non-interactive-install","content":"image tag"},{"heading":"non-interactive-install","content":"Pin nocodb/nocodb to a version. Default: latest."},{"heading":"non-interactive-install","content":"--pg="},{"heading":"non-interactive-install","content":"bundled or external"},{"heading":"non-interactive-install","content":"--pg-host=, --pg-port=, --pg-database=, --pg-user=, --pg-password="},{"heading":"non-interactive-install","content":"When --pg=external."},{"heading":"non-interactive-install","content":"--pg-ssl="},{"heading":"non-interactive-install","content":"managed, none, or /path/to/ca.pem"},{"heading":"non-interactive-install","content":"When --pg=external."},{"heading":"non-interactive-install","content":"--redis="},{"heading":"non-interactive-install","content":"bundled or external"},{"heading":"non-interactive-install","content":"--redis-url="},{"heading":"non-interactive-install","content":"redis://..."},{"heading":"non-interactive-install","content":"When --redis=external."},{"heading":"non-interactive-install","content":"Run bash noco.sh --help for the canonical list."},{"heading":"updating","content":"This pulls the latest images, restarts containers, and prunes old image layers."},{"heading":"common-operations","content":"If the stack won't start or you can't reach NocoDB, see Troubleshooting."},{"heading":"bringing-your-own-reverse-proxy-or-ssl","content":"If you already have nginx, Caddy, or a load balancer in front, run the installer with a blank domain (local mode). NocoDB then listens on port 8080. Forward the X-Forwarded-Proto and Host headers from your proxy so NocoDB generates correct callback URLs. For more control, see Custom infrastructure."},{"heading":"production-hardening-checklist","content":"Once the stack is up and you can sign in, walk through this checklist before opening it to real traffic:"},{"heading":"production-hardening-checklist","content":"Firewall. Allow only the ports you need (22 for SSH, 80+443 for HTTPS). On Ubuntu/Debian: sudo ufw allow OpenSSH && sudo ufw allow 80,443/tcp && sudo ufw enable. On RHEL family: firewall-cmd --add-service=ssh --add-service=http --add-service=https --permanent && firewall-cmd --reload."},{"heading":"production-hardening-checklist","content":"Verify secret-file permissions. The installer already restricts docker.env and nocodb/db.json to 600. Re-apply if you copied or edited them by hand:"},{"heading":"production-hardening-checklist","content":"SELinux (RHEL, Rocky, Alma, Fedora). Named volumes are relabeled by Docker automatically, so the data volumes need no action. The remaining bind mounts are the config files and the letsencrypt/ directory. If SELinux is in Enforcing mode (getenforce) and those are denied, add the :Z suffix to their entries in docker-compose.yml (e.g. ./letsencrypt:/letsencrypt:Z)."},{"heading":"production-hardening-checklist","content":"License activation outbound. NocoDB calls https://app.nocodb.com/api/v1/on-premise/agent over TCP 443 every 6 hours. If you filter egress by host or path, allowlist exactly that. For fully offline servers, see Airgapped license."},{"heading":"production-hardening-checklist","content":"Log rotation. Docker's json-file log driver grows unbounded by default. Add a global cap in /etc/docker/daemon.json:"},{"heading":"production-hardening-checklist","content":"Restart Docker (sudo systemctl restart docker) for the change to apply."},{"heading":"production-hardening-checklist","content":"systemd unit (optional but recommended). The default Compose stack restarts containers on Docker daemon restart, but a systemd unit makes the deployment itself a managed service. Create /etc/systemd/system/nocodb.service:"},{"heading":"production-hardening-checklist","content":"Enable with sudo systemctl daemon-reload && sudo systemctl enable --now nocodb.service."},{"heading":"production-hardening-checklist","content":"Healthcheck endpoint. NocoDB exposes GET /api/v1/health. Wire it into your monitoring system."},{"heading":"production-hardening-checklist","content":"Pin your image tags for production rather than tracking latest. See Pinning to a specific version."},{"heading":"production-hardening-checklist","content":"Schedule backups. See Backups. At minimum, a daily pg_dump plus an attachment tarball."},{"heading":"activating-an-enterprise-license","content":"Once NocoDB is running, sign up as the first user and go to Admin Panel → License to paste your key. See Purchase a license and License activation for the full flow."}],"headings":[{"id":"1-run","content":"1. Run"},{"id":"2-answer-34-prompts","content":"2. Answer 3–4 prompts"},{"id":"3-open-nocodb","content":"3. Open NocoDB"},{"id":"what-the-script-generates","content":"What the script generates"},{"id":"reviewing-the-script-before-running","content":"Reviewing the script before running"},{"id":"non-interactive-install","content":"Non-interactive install"},{"id":"updating","content":"Updating"},{"id":"common-operations","content":"Common operations"},{"id":"bringing-your-own-reverse-proxy-or-ssl","content":"Bringing your own reverse proxy or SSL"},{"id":"production-hardening-checklist","content":"Production hardening checklist"},{"id":"activating-an-enterprise-license","content":"Activating an enterprise license"}]},"url":"/docs/self-hosting/installation/single-server","title":"Single-server install","description":"Deploy NocoDB on a single server with Docker, Traefik, and automatic HTTPS."},{"_id":"/docs/self-hosting/maintenance/backups","structured":{"contents":[{"content":"Back up three things to fully protect your NocoDB instance: the Postgres database (your data and metadata), the attachments volume (uploaded files), and your config files (so you can rebuild the stack quickly)."},{"heading":"what-to-back-up","content":"Item"},{"heading":"what-to-back-up","content":"Where it lives"},{"heading":"what-to-back-up","content":"Why"},{"heading":"what-to-back-up","content":"Postgres database"},{"heading":"what-to-back-up","content":"Bundled: postgres_data named volume / External: your DB host"},{"heading":"what-to-back-up","content":"Contains all your bases, tables, rows, users, comments"},{"heading":"what-to-back-up","content":"Attachments"},{"heading":"what-to-back-up","content":"nocodb_data named volume (mounted at /usr/app/data)"},{"heading":"what-to-back-up","content":"Files users uploaded to attachment fields"},{"heading":"what-to-back-up","content":"Configuration"},{"heading":"what-to-back-up","content":"docker-compose.yml, docker.env, nocodb/db.json"},{"heading":"what-to-back-up","content":"Lets you rebuild the same stack on a fresh server"},{"heading":"what-to-back-up","content":"type: note"},{"heading":"what-to-back-up","content":"Named volumes persist across restarts and docker compose down. But a volume on the same host is not a backup. Always copy database dumps and attachment archives off the server."},{"heading":"bundled-postgres","content":"If you used --pg=bundled (or the Quickstart compose), back up the database container with pg_dump:"},{"heading":"bundled-postgres","content":"Restore on a fresh stack:"},{"heading":"bundled-postgres","content":"Schedule daily backups with cron:"},{"heading":"external-managed-postgres","content":"If you're using RDS, Cloud SQL, Azure Database, or another managed service, use the provider's snapshot/backup mechanism. Managed providers handle this far better than pg_dump:"},{"heading":"external-managed-postgres","content":"AWS RDS: Automated backups (recommended) + manual snapshots before major upgrades."},{"heading":"external-managed-postgres","content":"Google Cloud SQL: Automated backups and on-demand backups."},{"heading":"external-managed-postgres","content":"Azure Database for PostgreSQL: Backup and restore."},{"heading":"external-managed-postgres","content":"For self-managed external Postgres, run pg_dump from a host that can reach your DB."},{"heading":"attachments","content":"If your NocoDB stores attachments on the local filesystem (default), they live in the nocodb_data named volume. Compose prefixes volume names with the deployment directory, so confirm the real name first:"},{"heading":"attachments","content":"Back it up with a throwaway helper container that mounts the volume read-only:"},{"heading":"attachments","content":"If you've configured S3-compatible object storage (NC_S3_* env vars), your attachments live in that bucket rather than the nocodb_data volume, so the volume backup above doesn't apply. Back up the bucket instead, using your storage provider's tools: enable bucket versioning, lifecycle or cross-region replication rules, or scheduled bucket snapshots."},{"heading":"config-files","content":"Track these three files in version control:"},{"heading":"config-files","content":"If your server is destroyed, restoring is: provision new server → install Docker → git clone your config repo → docker compose up -d → restore Postgres dump → restore attachments tarball."},{"heading":"config-files","content":"type: info"},{"heading":"config-files","content":"Don't commit secrets. docker.env and nocodb/db.json contain credentials. Use a private repo, encrypt with git-crypt or sops, or store secrets separately and template the files at deploy time."},{"heading":"restoring-on-a-new-server","content":"Provision a fresh Linux VM with Docker."},{"heading":"restoring-on-a-new-server","content":"Run the Single-server install with the same domain settings."},{"heading":"restoring-on-a-new-server","content":"Stop NocoDB so the database is idle: docker compose stop nocodb worker."},{"heading":"restoring-on-a-new-server","content":"Restore Postgres: cat backup.sql | docker compose exec -T db psql -U nocodb nocodb."},{"heading":"restoring-on-a-new-server","content":"Restore attachments into the volume: docker run --rm -v nocodb_nocodb_data:/data -v \"$(pwd)\":/backup alpine tar -xzf /backup/attachments.tar.gz -C /data."},{"heading":"restoring-on-a-new-server","content":"Restart: docker compose start nocodb worker."},{"heading":"restoring-on-a-new-server","content":"Recovery time scales with the size of your database dump and attachments; a small instance restores in minutes."}],"headings":[{"id":"what-to-back-up","content":"What to back up"},{"id":"bundled-postgres","content":"Bundled Postgres"},{"id":"external-managed-postgres","content":"External (managed) Postgres"},{"id":"attachments","content":"Attachments"},{"id":"config-files","content":"Config files"},{"id":"restoring-on-a-new-server","content":"Restoring on a new server"}]},"url":"/docs/self-hosting/maintenance/backups","title":"Backups","description":"Back up your NocoDB instance: Postgres data, attachments, and config."},{"_id":"/docs/self-hosting/maintenance/upgrading","structured":{"contents":[{"content":"Upgrading NocoDB means pulling the latest Docker image and restarting your stack. Your data (in Postgres) and your config (in nocodb/db.json and docker.env) are preserved across the upgrade."},{"heading":"tldr","content":"If you used the Single-server install:"},{"heading":"tldr","content":"If you used the Quickstart or Custom infrastructure examples:"},{"heading":"tldr","content":"Both paths cause brief downtime while the containers restart."},{"heading":"before-upgrading","content":"Back up your Postgres database. See Backups. Always back up before a major version upgrade."},{"heading":"before-upgrading","content":"Check the Changelog for breaking changes since your current version."},{"heading":"before-upgrading","content":"On an older bind-mount install? If your deployment keeps data in ./postgres and ./nocodb instead of Docker named volumes, do the bind-mount to named-volume migration first, or NocoDB will start with an empty database."},{"heading":"step-by-step","content":"The installation wizard's ./update.sh does exactly these three steps."},{"heading":"migrating-from-bind-mounts-to-named-volumes","content":"Older NocoDB deployments stored data in host directories next to docker-compose.yml (./postgres, ./redis, ./nocodb). Current deployments use Docker-managed named volumes (postgres_data, redis_data, nocodb_data). If you pull a newer compose file, or re-run the installer, over an older bind-mount deployment, Docker mounts new, empty volumes and NocoDB starts with a fresh, empty database."},{"heading":"migrating-from-bind-mounts-to-named-volumes","content":"type: warn"},{"heading":"migrating-from-bind-mounts-to-named-volumes","content":"Your data is not lost: it stays in the old ./postgres and ./nocodb directories. But you must copy it into the new volumes before the first docker compose up -d on the new compose file, or NocoDB will initialize an empty database."},{"heading":"migrating-from-bind-mounts-to-named-volumes","content":"This is a one-time migration, and you only need it for the database and attachments. Redis holds cache and queue state, so a fresh, empty redis_data volume is fine."},{"heading":"migrating-from-bind-mounts-to-named-volumes","content":"type: info"},{"heading":"migrating-from-bind-mounts-to-named-volumes","content":"Using an external (managed) Postgres? Your database lives outside Docker and is unaffected, so skip the Postgres copy below and migrate only the attachments."},{"heading":"2-switch-to-the-new-compose-file-then-create-the-empty-volumes","content":"Re-run the installer, or replace docker-compose.yml with the named-volume version, then create the volumes without starting anything:"},{"heading":"2-switch-to-the-new-compose-file-then-create-the-empty-volumes","content":"Find the new volume names. Compose prefixes them with your deployment directory:"},{"heading":"3-copy-your-data-into-the-new-volumes","content":"A throwaway alpine container copies each old host directory into its volume. As long as the new stack uses the same Postgres major version as your old one, the raw data directory is compatible and transfers cleanly:"},{"heading":"3-copy-your-data-into-the-new-volumes","content":"If your directory is not named nocodb, replace nocodb_postgres_data and nocodb_nocodb_data with the names from step 2."},{"heading":"4-start-and-verify","content":"Sign in and confirm your bases, records, and attachments are all present. Once verified, the old data directories are safe to remove:"},{"heading":"4-start-and-verify","content":"Keep ./nocodb/, which still holds db.json, the database connection that the new compose mounts into the container."},{"heading":"4-start-and-verify","content":"type: note"},{"heading":"4-start-and-verify","content":"A raw data-directory copy only works within the same Postgres major version. If you are also moving to a new major version, pg_dump from the old stack and restore into the new one instead. See Backups."},{"heading":"pinning-to-a-specific-version","content":"Production deployments often pin to a specific version rather than tracking latest:"},{"heading":"pinning-to-a-specific-version","content":"Bump the tag, run docker compose up -d, and you've upgraded to that version."},{"heading":"pinning-to-a-specific-version","content":"Available tags are listed on Docker Hub."}],"headings":[{"id":"tldr","content":"TL;DR"},{"id":"before-upgrading","content":"Before upgrading"},{"id":"step-by-step","content":"Step-by-step"},{"id":"migrating-from-bind-mounts-to-named-volumes","content":"Migrating from bind mounts to named volumes"},{"id":"1-stop-the-old-stack","content":"1. Stop the old stack"},{"id":"2-switch-to-the-new-compose-file-then-create-the-empty-volumes","content":"2. Switch to the new compose file, then create the empty volumes"},{"id":"3-copy-your-data-into-the-new-volumes","content":"3. Copy your data into the new volumes"},{"id":"4-start-and-verify","content":"4. Start and verify"},{"id":"pinning-to-a-specific-version","content":"Pinning to a specific version"}]},"url":"/docs/self-hosting/maintenance/upgrading","title":"Upgrading","description":"Pull the latest image and restart. Your data and config are preserved."}]