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!

DMNO quickstart

  1. Setup dmno in your project

    Run this command in the root of your project:

    Terminal window
    npx dmno init

    This will create a .dmno folder in the root of your project with a config.mts file, including config items in your schema that we automatically imported from .env files. If in a monorepo, any additional services of your choice will get their own .dmno folders and associated files. Each .dmno folder looks something like this:

    • Directory/
      • Directory.dmno
        • Directory.typegen/ (generated types)
          • …
        • .env.local (your local overrides and sensitive values)
        • config.mts (your config schema)
        • tsconfig.json (dmno specific tsconfig)
      • … the rest of your folders
  2. Run dmno resolve in watch mode

    This will give you instant feedback while you author your config schema.

    Terminal window
    npm exec -- dmno resolve -w
  3. Write your schema

    The config schema and other settings live in the .dmno/config.mts files. dmno init does its best to scaffold out the initial version of this schema based on your existing .env files. Updating each item with a description, required, and sensitive is a great next step. You can then improve your schema over time, adding validations, and setting values from within the schema itself.

    Your initial should look something like this:

    .dmno/config.mts
    import { DmnoBaseTypes, defineDmnoService } from 'dmno';
    export default defineDmnoService({
    isRoot: true,
    schema: {
    PUBLIC_API_BASE_URL: {
    extends: DmnoBaseTypes.url,
    description: 'Base URL for the public API',
    },
    PUBLIC_GOOGLE_ANALYTICS_ID: {
    description: 'Google Analytics ID',
    },
    DATABASE_URL: {
    sensitive: true,
    extends: DmnoBaseTypes.url,
    description: 'Database connection string',
    },
    SECRET_API_KEY: {
    sensitive: true,
    },
    JWT_SECRET: {
    sensitive: true,
    },
    },
    });

    Check out the schema guide for full details.

    And if you would like more information on how we use .env files check out `.env’ file guide

  4. Configure framework specific integrations

    We provide drop-in integrations for many popular frameworks, and more are in the works. dmno init is smart enough to install the relevant integrations for each service. You can also read more about each integration on their respective pages and update them as needed.

    In this case of Astro or Vite, the integrations should work out of the box. In other cases, like Node.js or Next.js, you will need to update your package.json scripts to use dmno run so that your resolved config is passed to the script in question.

  5. Use DMNO_CONFIG to access your config

    We recommend migrating to DMNO_CONFIG as it provides helpful improvements like TypeScript autocompletion and IntelliSense.

    For example:

    // 😿 still works, but no type-safety, and will be a string
    if (!process.env.SOME_NUMBER) {
    throw new Error('Missing SOME_NUMBER env var');
    }
    const myConfigNum = parseFloat(process.env.SOME_NUMBER);
    // 🎉 easier, safer, full type-safety
    const myConfigNum = DMNO_CONFIG.SOME_NUMBER;
    const IS_PROD = DMNO_CONFIG.NODE_ENV === 'production';

    You could continue to use process.env/import.meta.env to access your config and still benefit from DMNO’s validation logic. But, DMNO_CONFIG gives you the full benefits of DMNO.