Configure from settings¶
get_storage is already settings-driven: it reads STORIX_PROVIDER and the
STORIX_<PROVIDER>_* variables (or a .env file) through pydantic-settings. So
the simplest configuration is environment variables plus a bare get_storage().
From the environment¶
STORIX_PROVIDER=azure
STORIX_AZURE_CONTAINER=raw
STORIX_AZURE_ACCOUNT_NAME=myaccount
STORIX_AZURE_CREDENTIAL=...
# Optional transfer sizes (every provider takes the first two). A byte count
# or a readable size: 4MiB is 4194304, 4MB is 4000000 - not synonyms.
STORIX_AZURE_READ_CHUNK_SIZE=4MiB
STORIX_AZURE_WRITE_CHUNK_SIZE=4MiB
STORIX_AZURE_READ_PREFETCH_SIZE=8MiB
# Optional, any provider: ceiling on parallel ranges per file (1 disables)
STORIX_MAX_TRANSFER_RANGES=8
from storix import get_storage
fs = get_storage() # provider and credentials come from the environment
From a config file¶
Non-secret settings can live in a file instead, which is how a project carries its own storage configuration without every developer exporting the same variables:
# storix.toml at the project root
provider = "s3"
max_transfer_ranges = 4
[s3]
bucket = "media"
region = "auto"
root = "/"
[local]
base = "./data"
storix.toml.example
in the repository is the complete reference: every provider, every setting,
profiles, and the [cli] table, with a comment on each. It is validated
against the real settings models by the test suite, so it cannot drift out
of date without failing the build.
storix looks for storix.toml, then .storix.toml, then a
pyproject.toml carrying [tool.storix], walking upward from the current
directory ruff-style; the first directory holding any of the three anchors
the project and stops the walk. Personal defaults live in ~/.config/storix/config.toml on Linux and macOS,
and %APPDATA%\storix\config.toml on Windows. XDG_CONFIG_HOME overrides
that on any platform.
An unknown key or table is an error naming the file, the key, and the known
set - a setting that silently does nothing is worse than one that refuses to
load. Relative paths in a project file resolve against that file; in the
user file they must be absolute or ~-prefixed, because a relative
machine-global path means nothing.
Precedence¶
Strongest first, verified in that order:
| source | example |
|---|---|
explicit keywords (and sx flags / --set) |
get_storage("local", base="./data") |
| a selected profile and its stage overlay | get_storage(profile="media") |
| the process environment | STORIX_LOCAL_BASE=/data |
the project .env |
STORIX_LOCAL_BASE=/data in .env |
| the nearest project config file | storix.toml |
| the XDG user config file | ~/.config/storix/config.toml |
| built-in defaults | ~/.storix |
A profile sits above the process environment on purpose: selecting one is an explicit act, and a stale exported variable must not quietly redirect it.
From your app's settings¶
To keep storage config next to the rest of your configuration, use the common
cached get_settings() pattern and derive one shared storage session from it.
Explicit overrides win over the environment:
"""Configure storix from settings.
get_storage is already settings-driven: it reads STORIX_PROVIDER and the
STORIX_<PROVIDER>_* variables (or a .env file) through pydantic-settings, so the
zero-code path is environment variables. To keep storage config next to the rest
of your app config, wrap it in your own BaseSettings and pass overrides, which
win over the environment.
"""
from __future__ import annotations
from functools import lru_cache
from pydantic_settings import BaseSettings, SettingsConfigDict
from storix import Storix, get_storage
def from_env() -> Storix:
# Set STORIX_PROVIDER=azure, STORIX_AZURE_CONTAINER=..., etc. (or a .env
# file), and get_storage picks them up with no code.
return get_storage()
class Settings(BaseSettings):
"""Storage config kept alongside the rest of the app's settings."""
model_config = SettingsConfigDict(env_prefix='APP_', env_file='.env')
storage_base: str = '~/app-data'
@lru_cache
def get_settings() -> Settings:
"""Build application settings once per process."""
return Settings()
@lru_cache
def get_fs() -> Storix:
"""Build one shared storage session from the application settings."""
settings = get_settings()
# Overrides beat the environment; each key mirrors the backend's kwarg.
return get_storage('local', base=settings.storage_base)
Overrides map one-to-one onto a backend's constructor keywords, so base= is a
LocalBackend option and container= an AzureBackend option. The transfer
sizes are the exception: read_chunk_size and write_chunk_size are understood
by every provider, and read_prefetch_size by every provider that fetches over
the network, so the same names work whichever backend you are on. All must be
positive. Defaults and what they trade against each other are in
Tune transfers.
The cached get_fs() is a process-level resource. Close it from your
application's shutdown hook. The FastAPI recipe shows the same
lifetime explicitly with lifespan.
Secrets in config files¶
A config file may reference a secret instead of holding one:
The reference resolves from the process environment first, then from the
project .env - the same file STORIX_* settings already come from, so a
secret kept there is not invisible to an env: reference. A variable set in
neither place is an error naming both. A literal secret in a project file is
refused outright (project files get committed); the XDG user file may hold
one, and warns if it is group- or world-readable.
Named profiles¶
A profile bundles a provider and its settings under a name, with optional stage overlays:
[profiles.media]
provider = "s3"
default_environment = "dev"
region = "auto"
[profiles.media.environments.dev]
bucket = "media-dev"
[profiles.media.environments.prod]
bucket = "media-prod"
The profile supplies the provider, so get_storage("gcs", profile="media")
is an error rather than an override; explicit keywords still win over the
profile's values. A project profile shadows a user profile of the same name
whole, so the effective profile is always readable from one file.
STORIX_PROFILE, STORIX_ENVIRONMENT, and a profile = "media" key pinned
in a config file are honored by sx only. In library code the selection is
always explicit, so get_storage("s3") beside get_storage("azure") means
what it says on every machine.
Profiles have their own page: Profiles and stages.