dynamic-config-nacos is a small reusable Python package for dynamic
configuration loading.
Its goal is to give application projects one consistent way to read configuration, whether the source is a local YAML file or a Nacos server.
Author: FrankTang (franktz2003@gmail.com)
License: MIT
- Uses local YAML as a fallback configuration source
- Fetches remote configuration from Nacos
- Supports automatic backend selection across
http,sdk_v2, andsdk_v3 - Refreshes in-memory configuration on updates on a best-effort basis
- Provides a lightweight
Confobject for dot-path and index-based access
pip install dynamic-config-nacosThe Python import name remains dynamic_config:
from dynamic_config import DynamicConfigProviderFor local workspace development with uv, downstream projects can also use a
path dependency to this package.
from dynamic_config import DynamicConfigProvider
provider = DynamicConfigProvider(local_yaml_path="configs/local.yaml")
provider.load_from_env()
app_name = provider.get("app.name")from dynamic_config import DynamicConfigProvider
provider = DynamicConfigProvider(local_yaml_path="configs/local.yaml")
provider.load_initial(None)
debug = provider.get("app.debug", False)$env:NACOS_SERVER_ADDR = "127.0.0.1:8848"
$env:NACOS_DATA_ID = "app.yaml"
$env:NACOS_GROUP = "DEFAULT_GROUP"from dynamic_config import DynamicConfigProvider
provider = DynamicConfigProvider(local_yaml_path="configs/local.yaml")
provider.load_from_env()
app_name = provider.get("app.name")DynamicConfigProvider currently requires a local_yaml_path value during
construction, but load_from_env() will override it if LOCAL_CONFIG_PATH is
set.
$env:LOCAL_CONFIG_PATH = "configs/dev.local.yaml"After load_from_env(), the library will use the path from
LOCAL_CONFIG_PATH.
conf = provider.conf
value1 = conf["a.b[0].c"]
value2 = conf.a.b[0].c
value3 = conf.get("a.x", "fallback")This package uses the standard library logging module and does not currently
accept a custom logger object from callers.
Internally it uses module-level loggers like this:
logger = logging.getLogger(__name__)That means the host application controls log output, handlers, formatting, and log levels:
import logging
logging.basicConfig(level=logging.INFO)Typical log events include:
warningwhen the local YAML file is missingwarningwhen Nacos returns a non-mapping YAML rootwarningfor invalid backend or polling interval valuesinfowhen a watcher has started, including the backend and polling interval for HTTP modeinfowhen a Nacos update has been appliedinfowhen a backend is auto-selectedexceptionwhen Nacos fetch, watcher startup, login, or version detection fails
If you use sdk_v2 or sdk_v3, you can route SDK logs to a dedicated path
without changing your application's root logger setup:
from dynamic_config import DynamicConfigProvider, NacosBackendType, NacosSettings
provider = DynamicConfigProvider(local_yaml_path="configs/local.yaml")
provider.load_initial(
NacosSettings(
server_addr="127.0.0.1:8848",
namespace=None,
data_id="app.yaml",
group="DEFAULT_GROUP",
backend=NacosBackendType.SDK_V3,
sdk_log_level="ERROR",
sdk_log_path="logs/nacos.log",
)
)You can also configure the same behavior through environment variables:
$env:NACOS_SDK_LOG_LEVEL = "ERROR"
$env:NACOS_SDK_LOG_PATH = "logs/nacos.log"sdk_log_path accepts either a directory or an explicit log file path. When
you pass a file path such as logs/nacos.log, the SDK logs are written to that
exact file.
If you install the current nacos-sdk-python 3.x line, the supported SDK path
in this package is sdk_v3.
In auto mode, the package now prefers sdk_v3 when that is the only
installed SDK-backed import path available. sdk_v2 is retained for older
environments that still provide the legacy nacos package import.
local_yaml_pathis currently a required constructor argument- The file itself does not need to exist
- If the file is missing, the library logs a warning and falls back to an empty
config
{} - If Nacos successfully returns a config, the local YAML file is not used for that load
In practice, the path behaves more like a local fallback location than a strict required input file.
The library's loading flow looks like this:
- Create
DynamicConfigProviderwith a local YAML path. - Call
load_from_env()to read Nacos-related environment variables. - If
NACOS_SERVER_ADDRis present, build aNacosSettingsobject. - Create a Nacos backend using explicit configuration or auto-detection.
- Try to fetch YAML content from Nacos first.
- If Nacos fails, returns empty content, or returns a non-mapping YAML root, fall back to the local YAML file.
- Store the final raw dictionary and wrap it in a
Confobject. - If the backend supports watching, start a watcher and refresh the in-memory config on updates.
When backend=AUTO, the package first tries to detect the Nacos server major
version over HTTP and then picks a preferred order:
- Nacos 2.x:
sdk_v2->sdk_v3->http - Nacos 3.x:
sdk_v3->sdk_v2->http - Detection failed:
sdk_v3->sdk_v2->http
After building that preferred order, the package filters out SDK paths that are
not actually importable in the current Python environment. For example, if only
v2.nacos is installed, auto skips sdk_v2 and goes straight to sdk_v3.
- Fetches config through the Nacos HTTP API
- Optionally logs in first to obtain an
accessToken - Starts a background polling thread
- Logs watcher startup with the active backend and polling interval
- Uses content MD5 to detect changes
- Logs when an updated config has been applied
- Tries multiple SDK import paths
- Tries both
get_configandgetConfig - Tries
add_config_watchers,add_config_watcher, andadd_listener
DynamicConfigProviderConfNullConfNULLNacosSettingsNacosBackendType
- English usage guide: how-to-use.md
- Chinese usage guide: how-to-use.zh-CN.md
- Chinese overview: README.zh-CN.md
- Changelog: CHANGELOG.md
- Homepage: https://github.com/franktz/dynamic-config-nacos
- Repository: https://github.com/franktz/dynamic-config-nacos
- Issues: https://github.com/franktz/dynamic-config-nacos/issues
- FrankTang
- Email: franktz2003@gmail.com
- License: MIT