{"id":32739061,"url":"https://github.com/microconfig/microconfig","last_synced_at":"2026-01-16T07:00:09.133Z","repository":{"id":37412720,"uuid":"169802047","full_name":"microconfig/microconfig","owner":"microconfig","description":"Modern tool for microservice configuration management","archived":false,"fork":false,"pushed_at":"2024-11-27T21:23:17.000Z","size":1938,"stargazers_count":308,"open_issues_count":0,"forks_count":18,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-10T11:12:18.727Z","etag":null,"topics":["cloud-config","configuration","configuration-framework","configuration-management","configuration-processor","microconfig","microservices","microservices-configuration","template-engine","yaml-configs"],"latest_commit_sha":null,"homepage":"https://microconfig.io","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/microconfig.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-08T21:35:02.000Z","updated_at":"2025-05-27T14:45:36.000Z","dependencies_parsed_at":"2024-09-17T01:25:07.914Z","dependency_job_id":"2e9c9bc1-a6dc-4171-89ad-34cd47b739da","html_url":"https://github.com/microconfig/microconfig","commit_stats":null,"previous_names":[],"tags_count":46,"template":false,"template_full_name":null,"purl":"pkg:github/microconfig/microconfig","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microconfig%2Fmicroconfig","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microconfig%2Fmicroconfig/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microconfig%2Fmicroconfig/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microconfig%2Fmicroconfig/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/microconfig","download_url":"https://codeload.github.com/microconfig/microconfig/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microconfig%2Fmicroconfig/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28477989,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T06:30:42.265Z","status":"ssl_error","status_checked_at":"2026-01-16T06:30:16.248Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloud-config","configuration","configuration-framework","configuration-management","configuration-processor","microconfig","microservices","microservices-configuration","template-engine","yaml-configs"],"created_at":"2025-11-03T09:00:49.843Z","updated_at":"2026-01-16T07:00:09.057Z","avatar_url":"https://github.com/microconfig.png","language":"Java","readme":"# Quick start\n\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.microconfig/microconfig-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.microconfig/microconfig-core)\n[![Slack badge](https://img.shields.io/badge/Join-Slack-brightgreen.svg)](https://join.slack.com/t/microconfig/shared_invite/zt-dflf2m0n-wOPVfAmk5eiHPn_9Omff7Q)\n\nWe recommend to start with [Microconfig Features guide](https://microconfig.io/features.html#/) and then continue reading this documentation.\n\n\n# Microconfig overview and features\n\nMicroconfig is intended to make it easy and convenient to manage configuration for microservices (or just for a big amount of services) and reuse the common part.\n\nIf your project consists of tens or hundreds of services you have to:\n\n* Keep the configuration for each service ideally separate from the code.\n* The configuration for different services can have common and specific parts. Also, the configuration for the same service in different environments can have common and specific parts.\n* A common part for different services (or for one service in different environments) should not be copied and pasted and must be easy to reuse.\n* It must be easy to understand how the resulting configuration is generated and based on which values the config placeholders are resolved.\n* Some configuration properties must be dynamic, calculated using an expression language.\n\nMicroconfig is written in Java, but it's designed to be used with systems written in any language. Microconfig just describes a format of configuration sources, syntax for placeholders, includes, excludes, overrides, an expression language for dynamic properties and an engine that can transform the config sources into simple *.yaml or *.properties files. Also it can resolve placeholders in arbitrary template files and show differences between config releases.\n\n## The difference between Microconfig and popular DevOps tools\n**Compared to config servers** (like Consul, Zookeeper, Spring Cloud Config):\n\nConfig servers solve the problem of dynamic distribution of configuration in runtime (can use http endpoints), but to distribute configuration you have to store it, ideally with changes in history and without duplication of common parts.\n\n**Compared to Ansible**:\n\nAnsible is a powerful, but much too general, engine for deployment management and doesn't provide a common and clean way to store configuration for microservices, and a lot of teams have to invent their own solutions based on Ansible.\n\nMicroconfig does one thing and does it well. It provides an approach, best practices for how to keep configuration for a big amount of services, and an engine to build config sources into result files.\n\nYou can use Microconfig together with any config servers and deployment frameworks. Configuration can be built during the deployment phase and the resulting plain config files can be copied to the filesystem, where your services can access them directly (for instance, Spring Boot can read configuration from *.yaml or *.properties), or you can distribute the resulting configuration using any config servers. Also, you can store not only application configuration but configuration used to run your services, and your deployment framework can read that configuration from Microconfig to start your services with the right parameters and settings.\n\n## Where to store the configuration\nIt’s a good practice to keep service configuration separate from code. It doesn't require you to rebuild services every time the configuration is changed and allows you to use the same service artefacts (for instance, *.jar) for all environments because it doesn’t contain any environment specific configuration. The configuration can be updated even in runtime without service source code changes.\n\nThe best way to follow this principle is to have a dedicated repository for configuration in your favorite version control system.  You can store configuration for all microservices in the same repository to make it easy to reuse a common part and be sure the common part is consistent for all your services.\n\n## Service configuration types\n\nIt's convenient to have different kinds of configuration and keep it in different files:\n* Deploy configuration (the configuration used by deployment tools that describes where/how to deploy your service, like artifact repository settings, container params).\n* Process configuration (the configuration used by deployment tools to start your service with right params, like memory limits, VM params, etc.).\n* Application configuration (the configuration that your service reads after start-up and uses in runtime).\n* Environment variables.\n* Secret configuration (note, you should not store in a VCS any sensitive information, like passwords. In a VCS you can store references(keys) to passwords, and keep passwords in special secured stores(like Vault) or at least in encrypted files on environment machines).\n* Library specific templates (for instance, Dockerfile, kafka.conf, cassandra.yaml, some scripts to run before/after your service start-up, etc.)\n\nMicroconfig detects the configuration type by the config file extension. The default configuration for config types:\n* `*.yaml` or `*.properties` for application configuration.\n* `*.deploy` for deployment configuration.\n* `*.k8s` for k8s configuration.\n* `*.proc` or `*.process` for process configuration. \n* `*.helm` for helm values.\n* `*.env` for environment variables.\n* `*.secret` for secret configuration.\n* For static files - see the 'Templates files' section.\n\nYou can use all the configuration types or only some of them. Also you can override the default extensions or define your own config types.\n\n# Basic folder layout\nLet’s take a look at a basic folder layout that you can keep in a dedicated repository.\n\nFor every service, you have to create a folder with a unique name(the name of the service). In the service directory, we will keep common and environment specific configurations.\n\nSo, let’s imagine we have 4 microservices: 'orders', 'payments', 'service-discovery', and 'api-gateway'. For convenience, we can group services by layers: 'infra' for infrastructure services and 'core' for our business domain services. The resulting layout will look like:\n\n```\nrepo\n└───core  \n│   └───orders\n│   └───payments\n│\t\n└───infra\n    └───service-discovery\n    └───api-gateway\n```\n\n## Configuration sources\n\nInside the service folder, you can create a configuration in `key=value` format. For the following examples, we will prefer using *.yaml, but Microconfig also supports *.properties. \n\nLet’s create the basic application and process configuration files for each service.\nYou can split configuration among several files, but for simplicity, we will create `application.yaml` and `process.proc` for each service. No matter how many base files are used, after the configuration build for each service and each config type, a single result file will be generated.\n\n```\nrepo\n└───core  \n│    └───orders\n│    │   └───application.yaml\n│    │   └───process.proc\n│    └───payments\n│        └───application.yaml\n│        └───process.proc\n│\t\n└───infra\n    └───service-discovery\n    │   └───application.yaml\n    │   └───process.proc\n    └───api-gateway\n        └───application.yaml\n        └───process.proc\n```\n\nInside process.proc we will store configuration that describes what your service is, and how to run it (your config files can have other properties, so don't pay attention to concrete values).\n\n**orders/process.proc**\n```properties\nartifact=org.example:orders:19.4.2 # partial duplication\njava.main=org.example.orders.OrdersStarter\njava.opts.mem=-Xms1024M -Xmx2048M -XX:+UseG1GC -XX:+PrintGCDetails -Xloggc:logs/gc.log # duplication\n```\n**payments/process.proc**\n```properties\nartifact=org.example:payments:19.4.2 # partial duplication\njava.main=org.example.payments.PaymentStarter\njava.opts.mem=-Xms1024M -Xmx2048M -XX:+UseG1GC -XX:+PrintGCDetails -Xloggc:logs/gc.log # duplication\ninstance.count=2\n```\n**service-discovery/process.proc**\n```properties\nartifact=org.example.discovery:eureka:19.4.2 # partial duplication \njava.main=org.example.discovery.EurekaStarter\njava.opts.mem=-Xms1024M -Xmx2048M # partial duplication \n```\n\nAs you can see we already have some small duplication (all services have '19.4.2' version, and two of them have the same java.ops params).  Configuration duplication is as bad as code duplication. We will see later how to do this in a better way.\n\nLet's see what application properties look like. In the comments we note what can be improved.\n\n**orders/application.yaml**\n```yaml\nserver.port: 9000\napplication.name: orders # better to get name from folder\norders.personalRecommendation: true\nstatistics.enableExtendedStatistics: true\nservice-discovery.url: http://10.12.172.11:6781 # are you sure url is consistent with SD configuration?\neureka.instance.prefer-ip-address: true  # duplication\ndatasource:\n  minimum-pool-size: 2  # duplication\n  maximum-pool-size: 10\n  url: jdbc:oracle:thin:@172.30.162.31:1521:ARMSDEV  # partial duplication\njpa.properties.hibernate.id.optimizer.pooled.prefer_lo: true  # duplication\n```\n**payments/application.yaml**\n```yaml\nserver.port: 8080\napplication.name: payments # better to get name from folder\npayments:\n  bookTimeoutInMs: 900000 # difficult to read. How long in minutes?\n  system.retries: 3\nconsistency.validateConsistencyIntervalInMs: 420000 # difficult to read. How long in minutes?\nservice-discovery.url: http://10.12.172.11:6781 # are you sure url is consistent with eureka configuration?\neureka.instance.prefer-ip-address: true  # duplication\ndatasource:\n  minimum-pool-size: 2  # duplication\n  maximum-pool-size: 5\ndatasource.url: jdbc:oracle:thin:@172.30.162.127:1521:ARMSDEV  # partial duplication\njpa.properties.hibernate.id.optimizer.pooled.prefer_lo: true # duplication\n```\n**service-discovery/application.yaml**\n```yaml\nserver.port: 6781\napplication.name: eureka\neureka:\n  client.fetchRegistry: false\n  server:\n    eviction-interval-timer-in-ms: 15000 # difficult to read\n    enable-self-preservation: false    \n```\n\nThe first bad thing - application files contain duplication. \nAlso, you have to spend some time to understand the application’s dependencies or its structure. \nFor instance, payment-service contains settings for:\n* service-discovery client\n* oracle db \n* application specific \n\nOf course, you can separate a group of settings by an empty line. But we can make it more readable and understandable.\n\n# Better config structure using #include\nOur services have a common configuration for service-discovery and database. To make it easy to understand the service's dependencies, let’s create folders for service-discovery-client and oracle-client and specify links to these dependencies from the core services.\n\n```\nrepo\n└───common\n|   └───service-discovery-client \n|   |   └───application.yaml\n|   └───oracle-client\n|       └───application.yaml\n|\t\n└───core  \n│   └───orders\n│   │   ***\n│   └───payments\n│       ***\n│\t\n└───infra\n    └───service-discovery\n    │   ***\n    └───api-gateway\n        ***\n```\n**service-discovery-client/application.yaml**\n```yaml\nservice-discovery.url: http://10.12.172.11:6781 # are you sure url is consistent with eureka configuration?\neureka.instance.prefer-ip-address: true \n```\n\n**oracle-client/application.yaml**\n```yaml\ndatasource:\n  minimum-pool-size: 2  \n  maximum-pool-size: 5\n  url: jdbc:oracle:thin:@172.30.162.31:1521:ARMSDEV  \njpa.properties.hibernate.id.optimizer.pooled.prefer_lo: true\n```\n\nAnd replace explicit configs with includes\n\n**orders/application.yaml**\n```yaml\n#include service-discovery-client, oracle-db-client\n\nserver.port: 9000\napplication.name: orders # better to get name from folder\norders.personalRecommendation: true\nstatistics.enableExtendedStatistics: true\n```\n\n**payments/application.yaml**\n```yaml\n#include service-discovery-client, oracle-db-client\n\nserver.port: 8080\napplication.name: payments # better to get name from folder\nconsistency.validateConsistencyIntervalInMs: 420000 # difficult to read. How long in minutes?\npayments:\n  bookTimeoutInMs: 900000 # how long in minutes?\n  system.retries: 3\n```\nTo include a component's configuration you need to specify only the component name, you don't need to specify its path. This makes the config layout refactoring easier. Microconfig will find a folder with the component's name and include the configuration from its files (if the folder name is not unique, Microconfig includes configs from each folder, but it's a good idea to keep a component name unique).\n\nSome problems still here, but we removed the duplication and made it easier to understand the service's dependencies.\n\nYou can override any properties from your dependencies.\nLet's override the order's connection pool size.\n\n**orders/application.yaml**\n```yaml    \n#include oracle-db-client\n\ndatasource.maximum-pool-size: 10\n***\n```\n\nNice. But order-service has a small part of its db configuration(pool-size), it's not that bad, but we can make the config semantically better.\nAlso you can see that order and payment services have a different ip for oracle.\n\norder: datasource.url: jdbc:oracle:thin:@172.30.162.\u003cb\u003e31\u003c/b\u003e:1521:ARMSDEV  \npayment: datasource.url: jdbc:oracle:thin:@172.30.162.\u003cb\u003e127\u003c/b\u003e:1521:ARMSDEV  \nAnd oracle-client contains settings for .31.\n\nOf course, you can override datasource.url in the payment/application.yaml. But this overridden property will contain a copy of another part of jdbc url and you will get all the standard 'copy-and-paste' problems. We would like to override only a part of the property. \n\nAlso it's better to create a dedicated configuration for order db and payment db. Both db configuration will include common-db config and override the 'ip' part of url. After that, we will migrate 'datasource.maximum-pool-size' from order-service to order-db, so order-service will contain only links to its dependencies and service-specific configs.\n\nLet’s refactor.\n```\nrepo\n└───common\n|   └───oracle\n|       └───oracle-common\n|       |   └───application.yaml\n|       └───order-db\n|       |   └───application.yaml\n|       └───payment-db\n|           └───application.yaml\n```\n\n**oracle-common/application.yaml**\n```yaml\ndatasource:\n  minimum-pool-size: 2  \n  maximum-pool-size: 5    \nconnection.timeoutInMs: 300000\njpa.properties.hibernate.id.optimizer.pooled.prefer_lo: true\n```\n**orders-db/application.yaml**\n```yaml\n#include oracle-common\n    \ndatasource:\n  maximum-pool-size: 10\n  url: jdbc:oracle:thin:@172.30.162.31:1521:ARMSDEV #partial duplication\n```\n**payment-db/application.yaml**\n```yaml\n#include oracle-common\n    \ndatasource.url: jdbc:oracle:thin:@172.30.162.127:1521:ARMSDEV #partial duplication\n```\n\n**orders/application.yaml**\n```yaml\n#include order-db\n***\n```\n\n**payments/application.yaml**\n```yaml\n#include payment-db\n```\n\nIncludes can be in one line or on different lines:\n\n```yaml\n#include service-discovery-client\n#include oracle-db-client, monitoring    \n```\n\n# Placeholders\n\nInstead of duplicating the value of some properties, Microconfig allows you to have a link (placeholder) to this value. \n\nLet's refactor the service-discovery-client config.\n\nInitial:\n\n**service-discovery-client/application.yaml**\n```yaml\nservice-discovery.url: http://10.12.172.11:6781 # are you sure host and port are consistent with SD configuration? \n```\n**service-discovery/application.yaml**\n```yaml\nserver.port: 6761 \n```\n\nRefactored:\n\n**service-discovery-client/application.yaml**\n```yaml\nservice-discovery.url: http://${service-discovery@ip}:${service-discovery@server.port}\n```\n**service-discovery/application.yaml**\n```yaml\nserver.port: 6761\nip: 10.12.172.11 \n```\nSo if you change the service-discovery port, all dependent services will get this update.\n\nMicroconfig has another approach to store service's ip. We will discuss it later. For now, it's better to set the 'ip' property in the service-discovery config file. \n\nThe Microconfig syntax for placeholders: `${componentName@propertyName}`. Microconfig forces you to specify the component name. This syntax is better than just a property name\n(like `${connectionSize}`), because it makes it obvious where to find the original placeholder value.\n\nLet's refactor oracle db config using placeholders and environment specific overrides.\n\nInitial:\n\n**oracle-common/application.yaml**\n```yaml    \ndatasource:\n  maximum-pool-size: 10\n  url: jdbc:oracle:thin:@172.30.162.31:1521:ARMSDEV \n```   \n\nRefactored:\n\n**oracle-common/application.yaml**\n```yaml\ndatasource:\n  maximum-pool-size: 10\n  url: jdbc:oracle:thin:@${this@oracle.host}:1521:${this@oracle.sid}\noracle:\n  host: 172.30.162.20\n  sid: ARMSDEV\n```\n**oracle-common/application.uat.yaml**\n```yaml\noracle.host: 172.30.162.80\n```\n\n**oracle-common/application.prod.yaml**\n```yaml\noracle:\n  host: 10.17.14.18\n  sid: ARMSPROD\n```\n\nAs you can see using placeholders we can override not only the whole property but also part of it.\n\nA placeholder can link to another placeholder. Microconfig can resolve them recursively and detect cyclic dependencies.\n\n## Temp properties\n\nIf you want to declare temp properties that will be used by placeholders only and you don't want them to be included in the result config file, you can declare them with `#var` keyword.\n\n**oracle-common/application.yaml**\n```yaml\ndatasource.url: jdbc:oracle:thin:@${this@oracle.host}:1521:${this@oracle.sid}\n#var oracle.host: 172.30.162.20\n#var oracle.sid: ARMSDEV\n```\n**oracle-common/application.uat.yaml**\n```yaml\n#var oracle.host: 172.30.162.80\n``` \n\nThis approach works with includes as well. You can #include oracle-common and then override 'oracle.host', and 'datasource.url' will be resolved based on the overridden value.\n\nIn the example below after the build process: datasource.url: jdbc:oracle:thin:@**100.30.162.80**:1521:ARMSDEV\n\n \n**orders-db/application.dev.yaml** \n```yaml   \n#include oracle-common\n \n#var oracle.host: 100.30.162.80         \n```\n## Removing base properties\nUsing `#var` you can remove properties from the result config file. You can include some config and override any property with #var to exclude it from the result config file.\n\nLet's remove 'payments.system.retries' property for 'dev' environment:\n\n**db-client/application.yaml**\n```yaml\ndatasource:\n  minimum-pool-size: 2  \n  maximum-pool-size: 5\n```\n**payments/application.yaml**\n```yaml\n#include db-client\n#var datasource.minimum-pool-size:  // will not be included into result config       \n```\n\n## Placeholder's default value\nYou can specify a default value for a placeholder using the following syntax: ${component@property:**defaultValue**}\n\nLet's set a default value for 'oracle host'\n\n**oracle-common/application.yaml**\n```yaml\ndatasource:\n  maximum-pool-size: 10\n  url: jdbc:oracle:thin:@${this@oracle.host:172.30.162.20}:1521:${this@oracle.sid}\n#var oracle.sid: ARMSDEV\n```\nNote, a default value can be a placeholder:\n `${component@property:${component2@property7:Missing value}}`\n \nIn the example Microconfig will try to:\n* resolve `${component@property}`\n* if the above is missing - resolve `${component2@property7}`\n* if the above is missing - return 'Missing value'\n\nIf a placeholder doesn't have a default value and that placeholder can't be resolved, Microconfig throws an exception with the detailed problem description.\n\n## Specials placeholders\nAs we discussed the syntax for placeholders looks like `${component@property}`.\nMicroconfig has several special useful placeholders:\n\n* `${this@env}` - returns the current environment name.\n* `${...@name}` - returns the component's name.\n* `${...@configDir}` - returns the full path of the component's config dir.\n* `${...@resultDir}` - returns the full path of the component's destination dir (the resulting files will be put into this dir).\n* `${this@configRoot}` - returns the full path of the config repository root dir (see `root` build param ).\n\nThere are some other environment descriptor related properties, we will discuss them later:\n* `${...@ip}`\n* `${...@portOffset}`\n* `${...@group}`\n* `${...@order}`\n\nNote, if you use a special placeholder with `${this@...}` then the value will be context dependent. Let's apply `${this@name}` to see why it's useful.\n\nInitial:\n\n**orders/application.yaml**\n```yaml\n#include service-discovery-client\n\napplication.name: orders\n```\n**payments/application.yaml**\n```yaml\n#include service-discovery-client\n\napplication.name: payments\n```\n\nRefactored:\n\n**orders/application.yaml**\n```yaml\n#include service-discovery-client\n```\n**payments/application.yaml**\n```yaml\n#include service-discovery-client\n```\n**service-discovery-client/application.yaml**\n```yaml\napplication.name: ${this@name}\n``` \n\n## Environment variables and system properties \nTo resolve environment variables use the following syntax: `${env@variableName}`\n\nFor example:\n```\n ${env@Path}\n ${env@JAVA_HOME}\n ${env@NUMBER_OF_PROCESSORS}\n```\n\nTo resolve Java system variables (System::getProperty) use the following syntax: `${system@variableName}`\n\nSome useful standard system variables:\n\n```\n ${system@user.home}\n ${system@user.name}\n ${system@os.name}\n```\n\nYou can pass your own system properties during Microconfig start with `-D` prefix (See 'Running config build' section)\n\nExample:\n```\n -DtaskId=3456 -DsomeParam3=value\n```\nThen you can access it: `${system@taskId}` or `${system@someParam3}`\n\n## Placeholders to another config type\n\nAs we discussed Microconfig supports different config types and detects the type by file extensions. Microconfig resolves placeholders based on properties of the **same config type** only.\n\nLet’s see the example how it works:\n\n‘orders’ has ‘service.port’ property in application.**yaml**, so you can declare a placeholder to this property from application config types only (*.yaml or *.properties). If you declare that placeholder in, for example, *.process files, Microconfig will not resolve it and throw an exception.\n\n**someComponent/application.yaml**\n```yaml\norderPort: ${orders@server.port} # works\n```\n**someComponent/application.process**\n```yaml\norderPort: ${orders@server.port} # doesn’t work\n```\n\nIf you need to declare a placeholder to a property from another config type you have to specify the config type using the following syntax: ${**configType**::component@property}.\n\nFor our example the correct syntax:\n\n**someComponent/application.process**\n```yaml\norderPort: ${app::orders@server.port}\n```\n\nMicroconfig default config types:\n* `app` – for *.yaml or *.properties\n* `process` – for *.proc or *.process\n* `deploy` – for *.deploy\n* `secret` – for *.secret\n* `env` – for *.env\n\n# Expression language\nMicroconfig supports math expressions, conditions and Java [String API](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html).\n\nLet's see some examples:\n\n```yaml\n#Better than 300000\nconnection.timeoutInMs: #{5 * 60 * 1000}\n\n#Microconfig placeholder and simple math\ndatasource.maximum-pool-size: #{${this@datasource.minimum-pool-size} + 10} \n\n#Using placeholder and Java String API\nmainClassNameWithoutPackage: #{'${this@java.main}'.substring('${this@java.main}'.lastIndexOf('.') + 1)}\n\nmonth: #{'${this@yyyy-MM-dd}'.split('-')[1]}\n\n#Condition\nreleaseType: #{'${this@version}'.endsWith('-SNAPSHOT') ? 'snapshot' : 'release'}\n\n```\n\n# Environment specific properties\nMicroconfig allows specifying environment specific properties (add/remove/override). For instance, you want to increase the connection-pool-size for dbs and increase the amount of memory for prod env.\nTo add/remove/override properties for the environment, you can create application.**${ENVNAME}**.yaml file in the config folder. \n\nLet's override connection pool size for 'dev' and 'prod' and add one new param for 'dev'. \n\n```\norder-db\n└───application.yaml\n└───application.dev.yaml\n└───application.prod.yaml\n```\n\n**orders-db/application.dev.yaml**\n```yaml   \ndatasource.maximum-pool-size: 15   \nhibernate.show-sql: true\n```\n\n**orders-db/application.prod.yaml**\n```yaml   \ndatasource.maximum-pool-size: 50\n```\n\nAlso, you can declare common properties for several environments in a single file. You can use the following filename pattern: application.**${ENV1.ENV2.ENV3...}**.yaml\n\nLet's create common properties for dev, dev2 and test environments.\n\n```\norder-db\n└───application.yaml\n└───application.dev.yaml\n└───application.dev.dev2.test.yaml\n└───application.prod.yaml\n```\n\n**orders-db/application.dev.dev2.test.yaml**\n```yaml   \nhibernate.show-sql: true\n```\n\nWhen you build config for a specific environment (for example 'dev') Microconfig will collect properties from:\n* application.yaml \n* then add/override properties from application.dev.{anotherEnv}.yaml.\n* then add/override properties from application.dev.yaml.\n \n## Profiles and explicit environment names for includes and placeholders\nAs we discussed you can create environment specific properties using the filename pattern: application.${ENV}.yaml. You can use the same approach for creating profile specific properties.\n\nFor example, you can create a folder for http client timeout settings:\n\n**timeout-settings/application.yaml**\n```yaml\ntimeouts:\n  connectTimeoutMs: 1000\n  readTimeoutMs: 5000\n```\nAnd some services can include this configuration:\n\n**orders/application.yaml**\n```yaml\n#include timeout-settings\n```\n**payments/application.yaml**\n```yaml\n#include timeout-settings\n```\n\nBut what if you want some services to be configured with a long timeout? Instead of the environment you can use the profile name in the filename:\n```\ntimeout-settings\n└───application.yaml\n└───application.long.yaml\n└───application.huge.yaml\n```\n**timeout-settings/application.long.yaml**\n```yaml\ntimeouts.readTimeoutMs: 30000\n```\n**timeout-settings/application.huge.yaml**\n```yaml\ntimeouts.readTimeoutMs: 600000\n```\n\nAnd specify the profile name with include:\n\n**payments/application.yaml**\n```yaml\n#include timeout-settings[long]\n```\n\nYou can use the profile/environment name with placeholders as well:\n\n```\n${timeout-settings[long]@readTimeoutMs}\n${kafka[test]@bootstrap-servers}\n```\n\nThe difference between environment specific files and profiles is only logic. Microconfig handles it in the same way.\n\n# Template files\nMicroconfig allows you to keep configuration files for any libraries in their specific format and resolve placeholders inside them.\nFor example, you want to keep logback.xml (or some other descriptor for your log library) and reuse this file with resolved placeholders for all your services. \n\nLet's create this file:\n```\nrepo\n└───common\n|    └───logback-template \n|         └───logback.xml\n```\n**logback-template/logback.xml**\n```xml\n\u003cconfiguration\u003e\n    \u003cappender class=\"ch.qos.logback.core.FileAppender\"\u003e\n        \u003cfile\u003elogs/${this@application.name}.log\u003c/file\u003e\n            \u003cencoder\u003e\n                \u003cpattern\u003e%d [%thread] %highlight(%-5level) %cyan(%logger{15}) %msg %n\u003c/pattern\u003e\n            \u003c/encoder\u003e\n    \u003c/appender\u003e    \n\u003c/configuration\u003e\n```\nSo we want every service to have its own logback.xml with resolved `${application.name}`. \nLet's configure the order and payment services to use this template.\n\n**orders/application.yaml**\n```yaml\n#include service-discovery-client\n\nmc.template.logback.fromFile: ${logback@configDir}/logback.xml # full path to logback.xml, @configDir - special placeholder property\n```\n\n**payments/application.yaml**\n```yaml\n#include service-discovery-client\n\nmc.template.logback.fromFile: ${logback@configDir}/logback.xml\n```  \n   \nIt's better to extract the common property `mc.template.logback.fromFile` to logback-template/application.yaml and then use #include.\n\n```\nrepo\n└───common\n|   └───logback-template \n|   └───logback.xml\n|   └───application.yaml\n```    \n**logback-template/application.yaml**\n```yaml   \nmc.template.logback.fromFile: ${logback@configDir}/logback.xml\n```\n**orders/application.yaml**\n```yaml\n#include service-discovery-client, logback-template\n```\n**payments/application.yaml**\n```yaml\n#include service-discovery-client, logback-template\n```  \n\nAs we saw in the above text the order and payment services include the `application.name` property from service-discovery-client.\nDuring the config build Microconfig will replace `${application.name}` inside logback.xml with the service's property value and copy the resulting file 'logback.xml' to the relevant folder for each service.\n\nIf you want to declare a property for a template only and don't want this property to be included into the result config file you can use `#var` keyword. \n\nIf you want to override the template destination filename you can use `mc.template.${templateName}.toFile=${someFile}` property. For example:  \n \n **logback-template/application.yaml**\n ```yaml   \n mc.template.logback:\n   fromFile: ${logback@configDir}/logback.xml\n   toFile: logs/logback-descriptor.xml\n ``` \n \nYou can use the absolute or the relative path for `toFile` property. The relative path starts from the resulting service config dir (see 'Running config build' section).\n\nSo the template dependency declaration syntax looks like:   \n```\nmc.template.${templateName}:\n  fromFile: ${sourceTemplateFile}\n  toFile: ${resolvedTemplateDestinationFile}\n```\n`${templateName}` - is used only for mapping `fromFile` and `toFile` properties.\n\nAlso, you can use a short one line syntax using -\u003e\n ```\n mc.template.${templateName}: ${sourceTemplateFile} -\u003e ${resolvedTemplateDestinationFile}\n ```\nUsing arrow notation you can also resolve directories with templates. This will resolve all files inside `${sourceTemplateDir}`. Source filename is used as target filename.\n ```\n mc.template.${templateName}: ${sourceTemplateDir}/* -\u003e ${resolvedTemplateDestinationDir}\n ```\nOr create multiple templates with different `${templateName}` from a single template file. \nNote the usage of `${templateName}` placeholder inside target filename to create different files based on template name.\n ```\n mc.template.[${templateName1},${templateName2}]: ${sourceTemplateFile} -\u003e ${resolvedTemplateDestinationDir}/targetName-${templateName}.xml\n ```\n\nLet's override the file that will be copied on the prod environment:\n```\nrepo\n└───common\n|   └───logback-template \n|       └───logback.xml\n|       └───logback-prod.xml\n|       └───application.yaml\n|       └───application.prod.yaml\n```\n**logback-template/application.prod.yaml**\n```yaml   \nmc.template.logback.fromFile: ${logback@configDir}/logback-prod.xml\n``` \n## Mustache template engine support\nIf resolving placeholders inside templates is not enough for you, you can use [Mustache template engine](https://mustache.github.io/mustache.5.html). With Mustache you can use loops, conditions and includes.\n\nLet's imagine we want to configure different Logback appenders on different environments. We can use condition 'appender.rolling' and override this value on different environments.\n\n```\n{{#appender.rolling}}\n    \u003cappender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\"\u003e\n        \u003cfile\u003elogs/${this@name}.log\u003c/file\u003e\n        \u003crollingPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy\"\u003e\n            \u003cfileNamePattern\u003elogs/${this@name}.%d{yyyy-MM-dd}.%i.log\u003c/fileNamePattern\u003e\n            \u003cmaxFileSize\u003e20MB\u003c/maxFileSize\u003e\n            \u003cmaxHistory\u003e30\u003c/maxHistory\u003e\n            \u003ctotalSizeCap\u003e1GB\u003c/totalSizeCap\u003e\n        \u003c/rollingPolicy\u003e\n    \u003c/appender\u003e\n{{/appender.rolling}}\n{{^appender.rolling}}\n    \u003cappender name=\"FILE\" class=\"ch.qos.logback.core.FileAppender\"\u003e\n        \u003cfile\u003elogs/${this@name}.log\u003c/file\u003e\n    \u003c/appender\u003e\n{{/appender.rolling}}\n```\n\n **logback-template/application.yaml**\n ```yaml   \nmc.mustache.logback.fromFile: ${logback@configDir}/logback.xml\n#var appender.rolling: true\n ``` \n\n **logback-template/application.test.yaml**\n ```yaml   \n#var appender.rolling: false\n ``` \n\nMicroconfig uses Mustache if the template declaration starts with `mc.mustache` prefix:\n```\nmc.mustache.logback.fromFile: ${logback@configDir}/logback.xml\n```\nor the template file has  `*.mustache` extension:  \n``` \nmc.template.logback:\n  fromFile: ${logback@configDir}/logback.mustache\n  toFile: logger.xml\n```\nor the short version\n``` \nmc.template.logback: ${logback@configDir}/logback.mustache -\u003e logger.xml\n```\n## Copy binary files\nIf you want to copy files as templates without placeholder resolving logic you can use the `mc.file.` prefix:\n``` \nmc.file.someBinary: ${this@configDir}/cert.jks -\u003e cert.jks\n``` \nor\n```\nmc.file.someBinary:\n  fromFile: ${this@configDir}/cert.jks\n  toFile: cert.jks\n```\n\n# Environment descriptor\nAs we discussed every service can have default and environment-specific configurations, also we can extract a common configuration to some components. \nDuring the build phase we want to build configs for a subset of our components, only for real services on a concrete environment.\nOf course, you can pass the environment name and the list of service names as parameters to build the configuration. But this is not very convenient if you want to build configuration for a large number of services.\n\nSo Microconfig allows specifying a list of service names on a special environment descriptor and then use only the environment name to build configs for all services listed on that descriptor.\n\nEnvironments descriptors must be in `${configRoot}/envs` folder.\n``` \nrepo\n└───components\n|   └───***   \n└───envs\n    └───base.yaml\n    └───dev.yaml\n    └───test.yaml\n    └───prod.yaml\n```\n\nLet's see the environment descriptor format:\n \n **envs/base.yaml**\n```yaml\norders:  \n  components:  \n    - order-db-patcher\n    - orders\n    - order-ui\n\npayments:\n  components:\n    - payment-db-patcher\n    - payments\n    - payment-ui\n\ninfra:\n  components: \n    - service-discovery\n    - api-gateway\n    - ssl-api-gateway\n    \nmonitoring:\n  components:\n    - grafana\n    - prometheus    \n```  \n\nenvironment name = filename\n```yaml\norders: # component group name\n  components:  \n    - order-db-patcher # component name(folder)\n    - orders # component name\n    - order-ui # component name\n``` \n\nOne environment can include another one and add/remove/override component groups:\n\n**envs/test.yaml**\n```yaml\ninclude: # include all groups from 'base' environment except 'monitoring'\n  env: base\n  exclude:\n   - monitoring\n\ninfra:\n  exclude:\n    - ssl-api-gateway # excluded ssl-api-gateway component from 'infra' group  \n  append:\n    - local-proxy # added new component into 'infra' group\n\ntests_dashboard: # added new component group 'tests_dashboard'\n  components:\n    - test-statistic-collector\n``` \n\nYou can use the optional param `ip` for the environment or component groups and then use it via `${componentName@ip}`.\n\nFor instance, `${orders@ip}` will be resolved to 12.53.12.67, `${payment-ui@ip}` will be resolved to 170.53.12.80.   \n```yaml\nip: 170.53.12.80 # default ip\n\norders:  \n  ip: 12.53.12.67 # ip overridden for the group\n  components:  \n    - order-db-patcher\n    - orders\n    - order-ui\n\npayments:  \n  components:\n    - payment-db-patcher\n    - payments\n    - payment-ui    \n```\n\nConsider configuring your deployment tool to read the environment descriptor to know which services to deploy.\n\n## Environment profiles\nYou can use env profiles if you want to create a new env based on another env[s].\nFor example, you have `prod` env and overrides for it and want to create `prod-europe` and `prod-usa` envs that include all properties from `prod` and can have their own overrides.\nThe easiest way to do this is to define `prod` profile in `prod-europe` and `prod-usa` env descriptors:\n\n**envs/prod.yaml**\n```yaml\ncore:\n  componets:\n   - order-service\n   - payment-service\n  ...\n```\n**envs/prod-europe.yaml**\n```yaml\ninclude\n env: prod # include all components from `prod` env\n\nprofiles: \n  - prod #include all configuration from prod envs\n ```\n\n**envs/prod-usa.yaml**\n```yaml\ninclude\n  env: prod # include all components from `prod` env\n\nprofiles: \n  - prod #include all configuration from prod envs\n  - usa #include overrides from `usa` profiles (app.usa.yaml)\n ```\n\nThe config override priority for all components from `prod-usa` env:\n* app.yaml `#without env`\n* app.prod.yaml `#overrides for prod env`\n* app.usa.yaml `#overrides for usa profile`\n* app.prod-usa.yaml `#overrides for prod-usa env`\n\n# Running the config build\nAs we discussed Microconfig has its own format for configuration sources. \nDuring the config build Microconfig inlines all includes, resolves placeholders, evaluates expression language, copies templates, and stores the result values into plain *.yaml or *.properties files to a dedicated folder for each service.\n\nTo run the build you can download Microconfig release from https://github.com/microconfig/microconfig/releases.\n\nThe required build params:\n* `-r` - full or relative config root dir. \n* either `-e` or `-envs`.\n    * `-e` - environment name (environment is used as a config profile, also as a group of services to build configs).\n    * `-envs` - a comma separated list of environment names **without spaces**. Use `*` for all environments, and `!` to exclude an environment. E.g. `-envs *,!base`.  \n`Tip: If you use zsh, be sure to escape the ! in your exclusions -\u003e e.g. -envs *,\\!base`\n\nOptional build params:\n* `-d` - full or relative build destination dir. Default = ${currentFolder}/build\n* `-stacktrace` - Show full stacktrace in case of exceptions. Values: true/false. Default: false  \n\nTo build configs not for the whole environment but only for specific services you can use the following optional params:\n* `-g` - a comma-separated list of component groups to build configs. \n* `-s` - a comma-separated list of services to build configs. \n\nCommand line params example (Java 8+ required):\n```\njava -jar microconfig.jar -r repo -e prod\n```\n\nTo add system properties use `-D`\n```\njava -DtaskId=3456 -DsomeParam=value -jar microconfig.jar -r repo -d configs -e prod\n```\n\nTo speed up the build up to 3 times you can add `-XX:TieredStopAtLevel=1` Java VM param. \nFor binary compiled distribution of MC(Mac, Linux, Win) you don't need XX:TieredStopAtLevel, it works ~5 times faster than jar version(cause we don't spend time in runtime to compile the code, but the peak performance is the same)\nAlthough the build time for even big projects with hundreds of services is about 1-3 seconds.\n```\njava -XX:TieredStopAtLevel=1 -jar microconfig.jar -r repo -e prod\n```\n\nLet's see examples of initial and destination folder layouts: \n\nInitial source layout:\n```\nrepo\n└───common\n|   └───logback-template \n|       └───logback.xml\n└───core  \n│   └───orders\n│   │   └───application.yaml\n│   │   └───process.proc\n│   └───payments\n│       └───application.yaml\n│       └───process.proc\n│\t\n└───infra\n    └───service-discovery\n    │   └───application.yaml\n    │   └───process.proc\n    └───api-gateway\n        └───application.yaml\n        └───process.proc\n```\nAfter build:\n```\nconfigs\n└───orders\n│   └───application.yaml\n│   └───process.yaml\n|   └───logback.xml\n└───payments\n│   └───application.yaml\n│   └───process.yaml\n|   └───logback.xml\n└───service-discovery\n│   └───application.yaml\n│   └───process.yaml\n|   └───logback.xml\n└───api-gateway\n    └───application.yaml\n    └───process.yaml\n    └───logback.xml\n```\n\nYou can try to build configs from the dedicated example repo: https://github.com/microconfig/microconfig-quickstart \n\n## Viewing differences between config versions \nDuring the config build, Microconfig compares newly generated files to files generated during the previous build for each service for each config type.\nMicroconfig can detect added/removed/changed properties. \n\nDiff for application.yaml is stored in diff-application.yaml, diff for process.yaml is stored in diff-process.yaml, etc.\n```\nconfigs\n└───orders\n│   └───application.yaml\n│   └───diff-application.yaml\n│   └───process.yaml\n│   └───diff-process.yaml\n│   └───logback.xml\n```\n\nThe Diff format:\n\n**diff-application.yaml**\n```yaml     \n+security.client.protocol: SSL # property has been added\n-connection.timeoutMs: 1000 # property has been removed\n server.max-threads: 10 -\u003e 35 # value has been changed from '10' to '35'\n```\n\n# YAML and Properties format support\nMicroconfig supports *.yaml and *.properties format for source and result configs.\nYou can keep a part of configuration in *.yaml files and another part in *.properties.\n\n```\nrepo\n└───core  \n│   └───orders\n│   │   └───application.yaml\n│   │   └───process.proc\n│   └───payments\n│       └───application.properties\n│       └───process.proc\n```\n\nYaml configs can have nested properties:\n```yaml\ndatasource:  \n  minimum-pool-size: 2  \n  maximum-pool-size: 5    \n  timeout:\n    ms: 10\n```      \n\nand lists:\n```yaml\ncluster.gateway:\n  hosts:\n    - 10.20.30.47\n    - 15.20.30.47\n    \n```\n\nYaml format configs will be built into *.yaml, property configs will be built into *.properties. If *.properties configs include *.yaml configs, the resulting file will be *.yaml.\nMicroconfig can detect the format based on separators (if a config file has extension neither *.yaml nor *.properties). If you use `:` key-value separator, Microconfig will handle it like *.yaml (`=` for *.properties).\n\n# Intellij IDEA plugin\nTo make configuration management a little bit easier you can use Microconfig Intellij IDEA plugin. The plugin can navigate to #include and placeholders' sources, show hints with resolved placeholders, and build configs from IDE.\n\nSee the documentation here: https://github.com/microconfig/microconfig-idea-plugin\n\n# Contributing\nIf you want to contribute to the project and make it better, your help is very welcome. You can request a feature or submit a bug via issues. Or submit a pull request.\n\nContributing to the documentation is very welcome too.\n\nYour Github 'Star' is appreciated!\n\nhttps://github.com/microconfig/microconfig\n\n# Contacts\n[Join our Slack!](https://join.slack.com/t/microconfig/shared_invite/zt-dflf2m0n-wOPVfAmk5eiHPn_9Omff7Q)\n\nsupport@microconfig.io\n","funding_links":[],"categories":["Configuration \u0026 Policy Automation","Configuration Management"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicroconfig%2Fmicroconfig","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicroconfig%2Fmicroconfig","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicroconfig%2Fmicroconfig/lists"}