Skip to content
DMNO
🚧 DMNO is still in beta! Use with caution!
✨ If you've tried DMNO or looked through the docs, let us know what you think!

Using DMNO with Netlify

At DMNO we love Netlify. This very site is hosted on it! That’s why we’re very excited to make it easier and safer to use environment variables in all of your Netlify-hosted projects.

This platform integration exposes a pre-made config schema and underlying types to interact with the env vars that Netlify injects while on their platform.

It also exposes a Netlify build plugin - which injects your resolved DMNO config into functions and edge functions. You may not need to use this plugin if you already have a build process that injects config values into your functions code before deployment.

Setup

Terminal window
npm add @dmno/netlify-platform

Netlify Config Schema

Netlify injects a set of read-only environment variables during its build process that provide information about the current build.

The @dmno/netlify-platform module exposes DMNO data types and a pre-made config schema object which you can use in your own schema. You can use the pickFromSchemaObject utility to pick only the env var keys that you need from the full list that Netlify injects. For example:

.dmno/config.mts
import { defineDmnoService, switchBy, pickFromSchemaObject } from 'dmno';
import { NetlifyEnvSchema } from '@dmno/netlify-platform/types';
export default defineDmnoService({
schema: {
...pickFromSchemaObject(NetlifyEnvSchema, 'CONTEXT', 'BUILD_ID'),
APP_ENV: {
value: switchBy('CONTEXT', {
_default: 'local',
'deploy-preview': 'staging',
'branch-deploy': 'staging',
production: 'production',
}),
},
},
});

Netlify build plugin

This package also includes a Netlify build plugin which automatically injects your resolved DMNO config into your Functions and Edge Functions.

You may also not need it for functions if you are running your own build process and have already handled bundling your DMNO config as static replacements at build time. In this case, you need to make sure that your config is injected into your build command - either via one of our integrations, or by using dmno run. If your build command is working locally, it probably will just work on Netlify.

You may need to use this plugin if:

  • you are authoring functions directly in netlify/functions and/or netlify/edge-functions folder(s) and you are relying on the netlify cli (netlify build) to bundle your code
  • you are using an external functions integration that handles creating/bundling your functions code, for example the Astro Netlify adapter

Feel free to reach out on Discord if you need help.

Build plugin installation

If you determine that you do need this build plugin, after installing the package itself, you need to add the plugin to your netlify.toml file. For example:

netlify.toml
# ...rest of your config
[[plugins]]
package = "@dmno/netlify-platform"

If you are authoring functions directly in netlify/functions/netlify/edge-functions folder(s), you must add an additional import if you want your functions to be able to run locally using netlify dev.

netlify/functions/example-fn.ts
import '../../.netlify/inject-dmno-config.js';
import type { Context, Config } from "@netlify/functions"
export default async (req: Request, context: Context) => {
console.log(DMNO_CONFIG.SOME_VAR);
// ...

If you are using an integration which already builds functions for you - like the Astro Netlify adapter - then you do not need to do anything.

Migrating from Netlify managed config

Should I set env vars in the Netlify UI at all?

Of course you can still set overrides and secrets within the Netlify UI if you like and rely on config values being injected that way.

However, we recommend migrating all of your config to DMNO itself by using switchBy to create branching logic based on the env vars injected by Netlify.

You can also use plugins - for example our Encrypted Vault and 1Password plugins - to handle sensitive config within your schema. Note that you will still set a single environment variable in the Netlify UI, to allow these plugins to access the rest of your secrets.

For example:

.dmno/config.mts
import { defineDmnoService, switchBy, pickFromSchemaObject } from 'dmno';
import { NetlifyEnvSchema } from '@dmno/netlify-platform/types';
import {
EncryptedVaultDmnoPlugin, EncryptedVaultTypes,
} from '@dmno/encrypted-vault-plugin';
// you could use a single vault, but it's best practice
// to split out prod secrets to limit access
const DevSecretsVault = new EncryptedVaultDmnoPlugin('vault/dev', {
key: configPath('..', 'DMNO_VAULT_KEY_DEV'),
name: 'dev',
});
const ProdSecretsVault = new EncryptedVaultDmnoPlugin('vault/prod', {
key: configPath('..', 'DMNO_VAULT_KEY_PROD'),
name: 'prod',
});
export default defineDmnoService({
schema: {
DMNO_VAULT_KEY_DEV: { extends: EncryptedVaultTypes.encryptionKey },
DMNO_VAULT_KEY_PROD: { extends: EncryptedVaultTypes.encryptionKey },
...pickFromSchemaObject(NetlifyEnvSchema, 'CONTEXT'),
APP_ENV: {
value: switchBy('CONTEXT', {
_default: 'local',
'deploy-preview': 'staging',
'branch-deploy': 'staging',
production: 'production',
}),
},
SOME_API_KEY: {
value: switchBy('APP_ENV', {
_default: 'not-sensitive-dev-key',
staging: DevSecretsVault.item(),
production: ProdSecretsVault.item(),
}),
},
},
});

Scopes

Note that Netlify’s built-in environment variable tooling has a concept of scopes and certain vars being applied/available at different times, for example during the build versus during function execution. There are also some limitations around env vars being injected into functions due to the nature of how those platforms are set up.

Using DMNO, we avoid all of that since we inject all of your resolved DMNO config at build time, and standardize access to your config regardless of the situation.

Note that any env vars set in the Netlify UI or netlify.toml must include the build scope to be noticed by DMNO - since we inject your config at build time.