createMany(project: string, environment: string, items: Array<VariableInput>, options?: ProductScope): Promise<CreatedVariablesResource>Creates up to 200 variables in a single request. This route is partial success by design: an item the server refuses is reported in skipped and the rest are still created, so read skipped and count instead of reading a resolved promise as full success. A batch in which every single item is refused does not resolve as a 201, it rejects with a 4xx carrying the per-item reasons.
An item is skipped rather than fatal when its name repeats inside the request, its value, type, visibility or default fails validation, it collides with an existing live variable, or it would push the environment past the 1000 variable cap. Items are processed in request order, so an overflow drops the tail rather than an arbitrary subset.
Every name is held to the same rule as create: ^[A-Za-z_][A-Za-z0-9_]*$, 1 to 100 characters, stored with exactly the casing you send. Names are compared without regard to case throughout, so two items in one batch that differ only in case collide with each other, and api_key collides with a live API_KEY. The SDK checks every name against that rule before sending, so a name that fails the shape or the length bound refuses the whole batch locally instead of coming back in skipped.
Ciphertext is checked per item, exactly as create does. A plaintext value or defaultValue anywhere in the batch aborts the whole request with 400 variable.ciphertext_invalid, naming the offending variable, and nothing is written. Encrypt every value before you send it.
Example
const result = await envless.variables.createMany('api', 'production', [
{ name: 'SENTRY_DSN', value: sentry },
{ name: 'REDIS_URL', value: redis }
])
console.log(result.count)
if (result.skipped.length > 0) console.log(result.skipped)Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | Yes | Project slug the environment belongs to. |
environment | string | Yes | Environment slug to create the variables in. |
items | Array<VariableInput> | Yes | Between 1 and 200 variables, each with a name matching ^[A-Za-z_][A-Za-z0-9_]*$ of 1 to 100 characters and a ciphertext value. |
options.product | string | No | Product slug, needed when the project slug is not unique in the workspace. |
options.signal | AbortSignal | No | Cancels the request. |
Returns
CreatedVariablesResource with created, skipped carrying a reason per name, and count of rows actually written.
Worth knowing
- A resolved call always created at least one variable. Everything the server refused is in
skipped, so inspect it on every call. - A batch where nothing was accepted rejects rather than resolving, so a rejection can mean bad names as easily as a transport failure. Read the per-item reasons before retrying.
- Names are case reserved, not case normalised. Sending
API_KEYandapi_keyin the same batch creates one of them and skips the other. - Every name is checked locally before anything is sent, so one unusable name rejects the whole batch with an
EnvlessApiErrorcarryingrequest.body_invalidinstead of arriving as askippedentry.
Required scopes
variables:write
Underlying endpoint
POST /projects/{slug}/environments/{environmentSlug}/variables/bulk
Request and response schema, every error code, and a live playground.
In Python
envless.variables.create_many()
The same method in envless-sdk, the Python SDK, with the same request, retries and errors.
In Ruby
Envless.variables.create_many
The same method in envless-sdk, the Ruby gem, with the same request, retries and errors.
In PHP
$envless->variables->createMany()
The same method in envless/sdk, the PHP SDK, with the same request, retries and errors.