View the example project on GitHub (opens new window)

package.json








 
 
 









 





{
  "name": "nodejs-server",
  "version": "0.0.0",
  "license": "MPL-2.0",
  "private": true,
  "main": "dist/index.js",
  "scripts": {
    "config:ci": "APP_CONFIG_SECRETS_KEY=`cat ci.asc` yarn app-config",
    "trust": "yarn config:ci secret trust",
    "dev": "ts-node-dev --files ./src/index.ts",
    "start": "node ./dist/index.js",
    "build": "tsc -b",
    "clean": "rm -rf dist *.tsbuildinfo"
  },
  "dependencies": {
    "@app-config/main": "2",
    "fastify": "3"
  },
  "devDependencies": {
    "@lcdev/tsconfig": "0.2",
    "ts-node-dev": "1",
    "typescript": "4"
  }
}

.app-config.schema.yml
















 







 











type: object
additionalProperties: false

required:
  - database
  - port

properties:
  port:
    $ref: "#/definitions/Port"
  database:
    type: object
    additionalProperties: false
    required:
      - username
      - password # encrypted
      - port
      - database
    properties:
      username:
        type: string
      password:
        type: string
        secret: true
      port:
        $ref: "#/definitions/Port"
      database:
        type: string

definitions:
  Port:
    type: integer
    minimum: 0
    maximum: 65535

.app-config.meta.yml



 




 



generate:
  - file: ./src/@types/lcdev__app-config/index.d.ts
teamMembers:
  - userId: Daniel Zarinski <daniel@lc.dev>
    publicKey: "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: OpenPGP.js v4.10.8\r\nComment: https://openpgpjs.org\r\n\r\nxjMEX7M4jxYJKwYBBAHaRw8BAQdAzCgPEIFywKDr+oOaEbVJE2jqh50vMfxA\r\nPz/D2kgdxM/NH0RhbmllbCBaYXJpbnNraSA8ZGFuaWVsQGxjLmRldj7CjwQQ\r\nFgoAIAUCX7M4jwYLCQcIAwIEFQgKAgQWAgEAAhkBAhsDAh4BACEJEGobs8AV\r\nvWE2FiEEO8f1YfyxR2A6r6SkahuzwBW9YTb8vAEA7KjqMh8lGGVun44r/ieg\r\ndqJtC42bsCcUntcitrgw7MABAMh6lYWS/rkuKBuaFjlOMhBHEDgdsvbTSTUX\r\nHIw+MicCzjgEX7M4jxIKKwYBBAGXVQEFAQEHQCUA3eQvF3CZ9I9ALaIF692V\r\n3s7+VVlbEjVVXfcLDmYWAwEIB8J4BBgWCAAJBQJfsziPAhsMACEJEGobs8AV\r\nvWE2FiEEO8f1YfyxR2A6r6SkahuzwBW9YTZ66gD/X+d8+hjNfHcW5xwHJ2FO\r\nnSI3BINdYnziIuYl4QIDbjcA/3pwrFytlUIxW+aM3MGMkSJ8A5pRCtf47YWH\r\n0dU6Z8cL\r\n=p59L\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n"
  - userId: CI <no-reply@lc.dev>
    publicKey: "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: OpenPGP.js v4.10.8\r\nComment: https://openpgpjs.org\r\n\r\nxjMEX7Xh9xYJKwYBBAHaRw8BAQdAD/oo/0/78VH8LHFejCyxmX7qpUdikC2Y\r\n9ERIOmAKcpLNFENJIDxuby1yZXBseUBsYy5kZXY+wo8EEBYKACAFAl+14fcG\r\nCwkHCAMCBBUICgIEFgIBAAIZAQIbAwIeAQAhCRBR9TO6eWTjuxYhBPgJGasb\r\ntsarWkPZ4lH1M7p5ZOO7tKUA/1S6tzzWYD87LwUIx/r+fbNC2pbwJYBVdUWr\r\n1RfyggtqAP4601DXUnfDHC/7Prb5n9RZ9A1cTY05GgWPEz0HQwOUA844BF+1\r\n4fcSCisGAQQBl1UBBQEBB0A4mG3enF+oJEtmUP3jqX4S4Ykq+B8j+lI9JtNg\r\nSQ0mFgMBCAfCeAQYFggACQUCX7Xh9wIbDAAhCRBR9TO6eWTjuxYhBPgJGasb\r\ntsarWkPZ4lH1M7p5ZOO7OjkA/jE737imk9gtfxOnDXbsOkPW2mCBRUttFcXQ\r\nC/KGO6OxAQCJAYZHdQsWead3XN8tdjehyz9lmab5GcOF4N/WZJnPCw==\r\n=lmdF\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n"
encryptionKeys:
  - revision: 1
    key: "-----BEGIN PGP MESSAGE-----\r\nVersion: OpenPGP.js v4.10.8\r\nComment: https://openpgpjs.org\r\n\r\n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\r\nyEKZCQ8GTw==\r\n=tUp5\r\n-----END PGP MESSAGE-----\r\n"

.app-config.yml














 
 

# Try it out! Run with APP_CONFIG_ENV=production

port: 8000

database:
  username: { $substitute: "${USER:-username}" }
  port: 3306
  database:
    $env:
      default: dev
      production: production
  password:
    $env:
      default: enc:1:wy4ECQMIsX1S2qXZKrXgN2dRmZBrWbmbsBdtMmZ3FwsmpCnCq5+RfN3UxNSZ20jX0j4B9dBnlPsKhYJM0/iPiSH3aT2y/Vvawbhe3KdaOK3tTzgV8Jl27fSvxI+FwCTGkM4cY0s74kleP7gq6Dchtw===Jftl # test
      production: enc:1:wy4ECQMIXJen9k4zRaXgl50+lqtJx9XXE+VASto5O0BMJv4DotrdxQNheXBW451B0kEBl9gkhN87rTYyjUAnisg58ECoR9PEUOldxjua4jE4T1PvpIUVGii3er7Cd+alJIC3M2+ffRX0UGuizP8zc/crXw===Y+3h # test123

index.ts


 












 










import fastify from 'fastify';
import { config, loadConfig } from '@app-config/main';

const server = fastify();

server.get('/', async () => {
  return { message: 'Hello world!' };
});

server.get('/config', async () => {
  return config;
});

async function main() {
  await loadConfig();
  await server.listen(config.port);

  console.log(`Listening on :${config.port}`);
}

main().catch((error) => {
  console.error(error);
  setTimeout(() => process.exit(1), 0);
});

Generated Type File






 
 
 
 

 
 
 
 
 
 



 


// AUTO GENERATED CODE
// Run app-config with 'generate' command to regenerate this file

import '@app-config/main';

export interface Index {
  database: Database;
  port: number;
}

export interface Database {
  database: string;
  password: string;
  port: number;
  username: string;
}

// augment the default export from app-config
declare module '@app-config/main' {
  export interface ExportedConfig extends Index {}
}