Skip to content

Fly.App reference

Source: src/Fly/App.ts

A Fly.App is a global namespace in your account. It contains Machines, Services, Secrets, IPs, and certificates.

Alchemy generates a unique name unless you pass one. url is https://{appName}.fly.dev. Nothing answers there until a Service or Machine publishes a proxy service and the App has an IpAssignment.

const site = yield* Fly.App("Site");

Pass name when you need a stable fly.dev hostname.

const site = yield* Fly.App("Site", {
name: "my-site",
});

Org defaults to the current token. Pass orgSlug to pin it.

const site = yield* Fly.App("Site", {
name: "my-site",
orgSlug: "my-org",
});

enableSubdomains: true turns on *.{appName}.fly.dev.

const site = yield* Fly.App("Site", {
name: "my-site",
enableSubdomains: true,
});

network is an optional 6PN name.

const site = yield* Fly.App("Site", {
name: "my-site",
network: "private",
});

Declare the App once. Pass it into every child. Resource-valued props accept the resource or an Effect producing it. Do not unwrap it just to pass it along.

src/app.ts
import * as Fly from "alchemy/Fly";
export const Site = Fly.App("Site");

Source: src/Fly/IpAssignment.ts

A Fly.IpAssignment is an address on an App. A Service publishes ports. Fly’s proxy load-balances {app}.fly.dev across Machines that publish a proxy service.

Identity is the allocated ip. There is no in-place update.

shared_v4 is a shared Anycast IPv4. It is free. This is what you want for fly.dev over IPv4. Yield it next to the Service.

export const PublicIp = Fly.IpAssignment("Shared", {
app: Site,
type: "shared_v4",
});

v6 is a dedicated IPv6. It is free.

export const V6 = Fly.IpAssignment("V6", {
app: Site,
type: "v6",
});

v4 is a billed dedicated IPv4. It may 400 if the org has no quota. Prefer shared_v4 or v6 in tests.

export const Dedicated = Fly.IpAssignment("Dedicated", {
app: Site,
type: "v4",
});

private_v6 is a Flycast address. Fly’s proxy serves it only inside the organization’s private network, at {app}.flycast. It is free. Use it for a backend that another App calls and the internet must not reach. Requests still go through the proxy, so blue/green cordoning, autostart, and autostop keep working. Allocate no public address on the same App.

export const Private = Fly.IpAssignment("Private", {
app: Backend,
type: "private_v6",
});

region pins a dedicated address. Shared Anycast ignores it. See Regions for the list of codes.

export const Dedicated = Fly.IpAssignment("Dedicated", {
app: Site,
type: "v4",
region: "iad",
});

serviceName binds the address to a Fly proxy service. Changing it replaces the assignment.

export const PublicIp = Fly.IpAssignment("Shared", {
app: Site,
type: "shared_v4",
serviceName: "http",
});

network names the private network a private_v6 address is reachable from. Create-only.

export const Private = Fly.IpAssignment("Private", {
app: Backend,
type: "private_v6",
network: "tenant-a",
});

orgSlug defaults to the current token’s org. It is not a replacement key.

export const PublicIp = Fly.IpAssignment("Shared", {
app: Site,
type: "shared_v4",
orgSlug: "my-org",
});

Allocate the address on the same App as the Service. api.url is https://{appName}.fly.dev.

export default Alchemy.Stack(
"MyApp",
{ providers: Fly.providers(), state: Alchemy.localState() },
Effect.gen(function* () {
const api = yield* Api;
const ip = yield* PublicIp;
return { url: api.url, ip: ip.ip };
}),
);