alchemy-vultr
v0.0.0
Published
Alchemy Effect provider for Vultr — every Vultr primitive as typed Infrastructure-as-Effects resources
Maintainers
Readme
alchemy-vultr
Alchemy Effect provider for Vultr — typed Infrastructure-as-Effects resources for Vultr primitives, built on Effect.
Layout matches Alchemy’s AWS / Cloudflare providers: root exports for auth and registration, plus one namespaced service folder per API surface (Vultr.Instance.Instance, Vultr.Firewall.Group, …).
Requirements
- Bun ≥ 1.2
- TypeScript 7
alchemy2.0.0-beta.64+effect4.0.0-beta.100+(the beta Alchemy peers)
Install
bun add alchemy-vultr alchemy effectQuick start
import * as Alchemy from "alchemy";
import * as Vultr from "alchemy-vultr";
import * as Effect from "effect/Effect";
export default Alchemy.Stack(
"VultrApp",
{
providers: Vultr.providers(),
state: Alchemy.localState(),
},
Effect.gen(function* () {
const stage = yield* Alchemy.Stage;
// Omit `name` so createPhysicalName embeds the stage (multi-stage safe).
const key = yield* Vultr.SshKey.SshKey("deploy", {
sshKey: "ssh-ed25519 AAAA...",
});
const vpc = yield* Vultr.Vpc.Vpc("net", {
region: "ewr",
description: `app-network-${stage}`,
});
const server = yield* Vultr.Instance.Instance("web", {
region: "ewr",
plan: "vc2-1c-1gb",
osId: 2284,
label: `web-${stage}`,
sshKeyIds: [key.id],
vpcIds: [vpc.id],
enableIpv6: true,
});
return {
stage,
instanceId: server.id,
mainIp: server.mainIp,
};
}),
);Stages
Same program, isolated environments (dev_$USER, staging, prod, pr-42):
bun alchemy deploy --stage staging
bun alchemy destroy --stage pr-42Vultr accounts are shared across stages — omit hard-coded name on SSH keys /
startup scripts so Alchemy’s physical names stay unique. See
docs/stages.md.
Service namespaces can also be imported directly (same pattern as alchemy/AWS/S3):
import * as Instance from "alchemy-vultr/Instance";
import * as Vpc from "alchemy-vultr/Vpc";Mix with another Alchemy cloud via Layer.mergeAll:
import * as Layer from "effect/Layer";
import * as Cloudflare from "alchemy/Cloudflare";
providers: Layer.mergeAll(Vultr.providers(), Cloudflare.providers()),See examples/basic.ts and Alchemy’s Custom Provider / Providers guides for the full lifecycle contract (reconcile, delete, list, diff, read, nuke).
export VULTR_API_KEY=...
bun alchemy deployOr run bun alchemy login and choose the Vultr auth provider (env or stored API key).
Authentication
| Method | How |
| --- | --- |
| Environment | VULTR_API_KEY (used automatically in CI) |
| Stored | alchemy login → Vultr → API Key |
| Tests / overrides | Credentials.fromApiKey("...") |
Resources
Include Vultr.providers() in your stack. Type IDs are Vultr.<Service>.<Resource> (with aliases for the previous flat names).
Compute
Instance.Instance, Instance.Ipv4, Instance.Template, BareMetal.Server, Snapshot.Snapshot, Snapshot.FromUrl, Iso.Iso, ReservedIp.ReservedIp, ReverseDns.Ipv4, ReverseDns.Ipv6
Networking
Vpc.Vpc, Vpc.NatGateway, Vpc.NatGatewayFirewallRule, Vpc.NatGatewayPortForwardingRule, Firewall.Group, Firewall.Rule, LoadBalancer.LoadBalancer
Kubernetes
Kubernetes.Cluster, Kubernetes.NodePool
Data
BlockStorage.Volume, BlockStorage.Snapshot, ObjectStorage.Subscription, ObjectStorage.Bucket, Vfs.Storage, Database.Database, Database.User, Database.Db, Database.Replica, Database.ConnectionPool, Database.Topic, Database.Quota, Database.Connector
DNS & CDN
DNS.Domain, DNS.Record, CDN.PullZone, CDN.PushZone
Platform
SshKey.SshKey, StartupScript.StartupScript, User.User, ApiKey.ApiKey, ContainerRegistry.Registry, Inference.Subscription, Organization.Organization, Organization.Group, Organization.Invitation, Organization.Policy, Organization.Role, Organization.RoleTrust, Oidc.Issuer, Oidc.Provider, Oidc.Token
Catalog helpers
Read-only lookups (not stack resources) live under Vultr.Catalog:
const regions = yield* Vultr.Catalog.listRegions();
const plans = yield* Vultr.Catalog.listPlans({ type: "vhf" });Development
This repo vendors Alchemy and Effect as git submodules under repos/ for local reference. Provider work follows Alchemy’s resource factory and beta.64 conventions — see AGENTS.md and processes/Vultr/.
git submodule update --init --recursive
bun install
bun run typecheck
bun run lint # biome check (lint + format)
bun run format # biome format --write
bun run test
bun run buildLive provider tests (factory shape: deploy → out-of-band verify → update → destroy).
Requires VULTR_API_KEY. If the key has IP allowlisting, allow this runner’s
egress IP or disable the allowlist — see docs/api-discrepancies.md.
export VULTR_API_KEY=...
bun run test:live # sets CI=1 so AuthProvider reads the env keyPublishing
Versioning and release notes use Changesets. npm publish uses Trusted Publishing (OIDC) — no NPM_TOKEN (GAT deprecation).
| Workflow | When | What |
| --- | --- | --- |
| ci.yml | PRs / pushes | typecheck, lint, test, build |
| publish.yml | push to main | open/update Version Packages PR, or publish + GitHub Release |
Contributor flow
# On your feature branch, after meaningful changes:
bun run changeset
# pick patch | minor | major, write a short summary → commit the new .changeset/*.mdMerging to main with pending changesets opens a Version Packages PR that bumps package.json, updates CHANGELOG.md (with GitHub PR links), and deletes consumed changesets. Merging that PR:
- Publishes to npm via OIDC (
changeset publish) - Creates a GitHub Release whose body is the new changelog entry
- Pushes the
vX.Y.Zgit tag
One-time npmjs.com setup
- Ensure the package exists on npm (first version can be a manual
npm publishif Trusted Publisher UI requires it). - Package Settings → Trusted Publisher → GitHub Actions:
- Organization/user:
Kennybll - Repository:
alchemy-vultr - Workflow filename:
publish.yml(filename only — must match exactly) - Allowed actions:
npm publish
- Organization/user:
- After a successful Actions publish, revoke any old automation tokens and prefer Require two-factor authentication and disallow tokens under Publishing access.
License
MIT
