# Floci integration

<Badge text="⭐ Community Toolkit" variant="tip" size="large" />

<ThemeImage
  light={flociIcon}
  dark={flociLightIcon}
  alt="Floci logo"
  width={100}
  height={100}
  zoomable={false}
  classOverride="float-inline-left icon"
/>

The Aspire Floci hosting integration enables you to model [Floci](https://floci.io) — a family of high-performance local cloud emulators — as container resources in your Aspire application. Floci ships one image per cloud, each API-compatible with its respective provider:

- **`floci/floci`** — AWS, 65+ services including Lambda, S3, DynamoDB, SQS, and SNS
- **`floci/floci-az`** — Azure, including Blob/Queue/Table Storage, Cosmos DB, Functions, Event Hubs, and Service Bus
- **`floci/floci-gcp`** — GCP, including Pub/Sub, Firestore, Datastore, Storage, Secret Manager, and Cloud Functions

Every API is available in both C# and TypeScript AppHosts. The integration supports:

- Running any combination of the AWS, Azure, and GCP emulators as container resources in the same Aspire application.
- Automatic environment variable injection for dependent services to connect to the emulated cloud.
- Customizable port and cloud-specific defaults (region, account ID, project ID).
- Data persistence with named volumes or bind mounts.
- Docker-socket access for container-backed services (Lambda, Azure Functions, Cloud Run/Cloud SQL).
- An optional [Floci UI](https://github.com/floci-io/floci-ui) web console, attachable to one or all three clouds at once.
- Custom Quarkus configuration files for the AWS emulator.
- HTTPS with Aspire-managed certificates for the AWS and Azure emulators.

## Installation

To start building an Aspire app that uses Floci, install the [📦 CommunityToolkit.Aspire.Hosting.Floci](https://www.nuget.org/packages/CommunityToolkit.Aspire.Hosting.Floci) NuGet package:

```bash title="Terminal"
aspire add communitytoolkit-floci
```

Or, choose a manual installation approach:

```csharp title="AppHost.cs"
#:package CommunityToolkit.Aspire.Hosting.Floci@*
```

```xml title="AppHost.csproj"
<PackageReference Include="CommunityToolkit.Aspire.Hosting.Floci" Version="*" />
```

```bash title="Terminal"
aspire add communitytoolkit-floci
```

This updates your `aspire.config.json` with the Floci hosting integration package:

```json title="aspire.config.json" ins={3}
{
  "packages": {
    "CommunityToolkit.Aspire.Hosting.Floci": "*"
  }
}
```

### Add a Floci resource

Each cloud has its own dedicated method — `AddFlociAws`/`addFlociAws`, `AddFlociAzure`/`addFlociAzure`, and `AddFlociGcp`/`addFlociGcp` — and each returns its own resource type. Add whichever clouds your app depends on; they can coexist in the same AppHost.

#### Add a Floci resource for AWS

```csharp title="AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var aws = builder.AddFlociAws("floci-aws");

var api = builder.AddProject<Projects.Api>("api")
    .WithReference(aws)
    .WaitFor(aws);

builder.Build().Run();
```

```typescript title="apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const aws = await builder.addFlociAws('floci-aws');

const api = await builder.addProject('api', '../Api/Api.csproj');
await api.withFlociAwsReference(aws).waitFor(aws);

await builder.build().run();
```

`WithReference(aws)`/`withFlociAwsReference(aws)` uses the standard Aspire connection string injection and automatically injects the AWS environment variables listed in [Environment variables](#environment-variables) into the dependent resource.

#### Add a Floci resource for Azure

```csharp title="AppHost.cs"
var azure = builder.AddFlociAzure("floci-az");

builder.AddProject<Projects.Api>("api")
    .WithReference(azure)
    .WaitFor(azure);
```

```typescript title="apphost.mts"
const azure = await builder.addFlociAzure('floci-az');

const api = await builder.addProject('api', '../Api/Api.csproj');
await api.withFlociAzureReference(azure).waitFor(azure);
```

#### Add a Floci resource for GCP

```csharp title="AppHost.cs"
var gcp = builder.AddFlociGcp("floci-gcp", defaultProjectId: "my-project");

builder.AddProject<Projects.Api>("api")
    .WithReference(gcp)
    .WaitFor(gcp);
```

```typescript title="apphost.mts"
const gcp = await builder.addFlociGcp('floci-gcp', {
  defaultProjectId: 'my-project',
});

const api = await builder.addProject('api', '../Api/Api.csproj');
await api.withFlociGcpReference(gcp).waitFor(gcp);
```

**Note:** In C#, each cloud contributes a `WithReference` overload, so the compiler
  selects the correct overload from the resource type. TypeScript bindings don't
  support overload resolution, so use `withFlociAwsReference`,
  `withFlociAzureReference`, or `withFlociGcpReference`.

### Configure resource properties

**AWS** accepts the following customizable properties:

- **Port**: The host port Floci listens on (default: 4566)
- **Default Region**: AWS region for the emulator (default: `us-east-1`)
- **Default Account ID**: AWS account ID for the emulator (default: `000000000000`)

```csharp title="AppHost.cs"
var aws = builder.AddFlociAws("floci-aws",
    defaultRegion: "eu-west-1",
    defaultAccountId: "123456789012");
```

```typescript title="apphost.mts"
const aws = await builder.addFlociAws('floci-aws', {
  defaultRegion: 'eu-west-1',
  defaultAccountId: '123456789012',
});
```

**GCP** accepts the following customizable properties:

- **Port**: The host port Floci listens on (default: 4588)
- **Default Project ID**: GCP project ID for the emulator (default: `floci-local`)

```csharp title="AppHost.cs"
var gcp = builder.AddFlociGcp("floci-gcp",
    defaultProjectId: "my-project");
```

```typescript title="apphost.mts"
const gcp = await builder.addFlociGcp('floci-gcp', {
  defaultProjectId: 'my-project',
});
```

**Azure** only accepts a custom port; there's no region/account/project equivalent to configure.

### Enable Lambda, Azure Functions, and container-backed services

Each emulator needs access to the Docker socket to launch sibling containers for its container-backed services (AWS Lambda, Azure Functions, GCP Cloud Run/Cloud SQL). `WithDockerSocket`/`withDockerSocket` works the same way on all three clouds:

```csharp title="AppHost.cs"
var aws = builder.AddFlociAws("floci-aws")
    .WithDockerSocket();

var azure = builder.AddFlociAzure("floci-az")
    .WithDockerSocket();

var gcp = builder.AddFlociGcp("floci-gcp")
    .WithDockerSocket();
```

```typescript title="apphost.mts"
const aws = await builder.addFlociAws('floci-aws');
await aws.withDockerSocket();

const azure = await builder.addFlociAzure('floci-az');
await azure.withDockerSocket();

const gcp = await builder.addFlociGcp('floci-gcp');
await gcp.withDockerSocket();
```

On non-standard Docker installations (e.g., Podman, Rancher Desktop), pass the socket path explicitly:

```csharp title="AppHost.cs"
var aws = builder.AddFlociAws("floci-aws")
    .WithDockerSocket("/run/user/1000/podman/podman.sock");
```

```typescript title="apphost.mts"
const aws = await builder.addFlociAws('floci-aws');
await aws.withDockerSocket({ socketPath: '/run/user/1000/podman/podman.sock' });
```

### Add data persistence to Floci

By default each emulator stores all state in memory. This information is lost when you restart the application. If you want state to persist across app restarts you can use either a data volume or a data bind mount. They are available on all three clouds.

**Note:** For more information on data volumes and details on why they’re preferred over
  bind mounts, see [Docker docs:
  Volumes](https://docs.docker.com/engine/storage/volumes).

#### Data volume (recommended)

Data volumes automatically switch Floci from in-memory to persistent mode:

```csharp title="AppHost.cs"
var aws = builder.AddFlociAws("floci-aws")
    .WithDataVolume("floci-data");

var azure = builder.AddFlociAzure("floci-az")
    .WithDataVolume("floci-az-data");

var gcp = builder.AddFlociGcp("floci-gcp")
    .WithDataVolume("floci-gcp-data");
```

```typescript title="apphost.mts"
const aws = await builder.addFlociAws('floci-aws');
await aws.withDataVolume('floci-data');

const azure = await builder.addFlociAzure('floci-az');
await azure.withDataVolume('floci-az-data');

const gcp = await builder.addFlociGcp('floci-gcp');
await gcp.withDataVolume('floci-gcp-data');
```

#### Bind mount

Alternatively, use a host bind mount for directory-based storage:

```csharp title="AppHost.cs"
var aws = builder.AddFlociAws("floci-aws")
    .WithDataBindMount("/path/to/data");
```

```typescript title="apphost.mts"
const aws = await builder.addFlociAws('floci-aws');
await aws.withDataBindMount('/path/to/data');
```

Either approach persists resource state across container restarts and allows local inspection of the stored state.

### Use the cloud SDKs to interact with Floci

Once a Floci resource is running and referenced by your service, use the matching cloud SDK as you normally would. `WithReference` in C# or the cloud-specific `withFloci*Reference` method in TypeScript injects provider-specific settings into the dependent resource.

AWS and GCP SDKs read their emulator endpoint and region or project settings from the injected environment variables. Azure Storage clients don't automatically read `AZURE_STORAGE_CONNECTION_STRING`; construct the client from the injected value:

```csharp title="Program.cs"
using Azure.Storage.Blobs;

var builder = WebApplication.CreateBuilder(args);

var azureStorageConnectionString =
    builder.Configuration["AZURE_STORAGE_CONNECTION_STRING"]
    ?? throw new InvalidOperationException(
        "AZURE_STORAGE_CONNECTION_STRING is not configured.");

builder.Services.AddSingleton(
    new BlobServiceClient(azureStorageConnectionString));
```

After configuring the provider's SDK client, interact with Floci as you would with the corresponding cloud service. For example, against the AWS emulator:

```csharp title="Service.cs"
using Amazon.S3;
using Amazon.S3.Model;

public class StorageService
{
    private readonly IAmazonS3 _s3Client;

    public StorageService(IAmazonS3 s3Client)
    {
        _s3Client = s3Client;
    }

    public async Task CreateBucketAsync(string bucketName)
    {
        await _s3Client.PutBucketAsync(new PutBucketRequest
        {
            BucketName = bucketName
        });
    }

    public async Task UploadObjectAsync(string bucketName, string key, Stream stream)
    {
        await _s3Client.PutObjectAsync(new PutObjectRequest
        {
            BucketName = bucketName,
            Key = key,
            InputStream = stream
        });
    }
}
```

### Floci UI web console

Run the [Floci UI](https://github.com/floci-io/floci-ui) web console alongside an emulator to browse its hosted resources. `WithFlociUI`/`withFlociUI` is available on all three cloud resource types:

```csharp title="AppHost.cs"
var floci = builder.AddFlociAws("floci")
    .WithFlociUI();
```

```typescript title="apphost.mts"
const floci = await builder.addFlociAws('floci');
await floci.withFlociUI();
```

Customize the container name or pin the host port:

```csharp title="AppHost.cs"
var floci = builder.AddFlociAws("floci")
    .WithFlociUI(ui => ui.WithHostPort(14500), containerName: "my-floci-ui");
```

```typescript title="apphost.mts"
const floci = await builder.addFlociAws('floci');
await floci.withFlociUI({
  containerName: 'my-floci-ui',
  configureContainer: async (ui) => {
    await ui.withHostPort({ port: 14500 });
  },
});
```

**Note:** Floci also has a built-in mechanism to launch the UI as a sidecar container on
  demand, but that relies on Floci itself talking to the Docker socket and
  self-discovered endpoints, which does not play well with Aspire's DCP-managed
  container networking. `WithFlociUI`/`withFlociUI` runs the UI as a first-class
  Aspire resource instead.

#### Attach all three clouds to one console

A single UI console can attach to any combination of clouds. Call `WithFlociUI`/`withFlociUI` on whichever cloud creates the console, then attach the others with `WithReference` in C# or the provider-specific reference method in TypeScript:

```csharp title="AppHost.cs"
var aws = builder.AddFlociAws("floci-aws");
var azure = builder.AddFlociAzure("floci-az");
var gcp = builder.AddFlociGcp("floci-gcp");

aws.WithFlociUI(configureContainer: ui =>
{
    ui.WithReference(azure);
    ui.WithReference(gcp);
});
```

```typescript title="apphost.mts"
const aws = await builder.addFlociAws('floci-aws');
const azure = await builder.addFlociAzure('floci-az');
const gcp = await builder.addFlociGcp('floci-gcp');

await aws.withFlociUI({
  configureContainer: async (ui) => {
    await ui.withAzureReference(azure);
    await ui.withGcpReference(gcp);
  },
});
```

The UI container (`floci/floci-ui`) is added as a child resource of whichever cloud resource created it, wired to each attached cloud's endpoint over the container network (`FLOCI_ENDPOINT`/`FLOCI_AZURE_ENDPOINT`/`FLOCI_GCP_ENDPOINT`), and is excluded from the deployment manifest — it's a local development tool only.

**Note:** In C#, `WithReference` is overloaded for each Floci UI cloud type. TypeScript
  uses `withAwsReference`, `withAzureReference`, or `withGcpReference`.

### Quarkus configuration file (AWS only)

Mount a custom `application.yml` to tune any Floci setting that does not have a dedicated extension method. The file is injected read-only at `/deployments/config/application.yml` — the standard Quarkus Docker config override location. This is currently only available on the AWS emulator:

```csharp title="AppHost.cs"
var floci = builder.AddFlociAws("floci")
    .WithConfigFile("./floci.yml");
```

```typescript title="apphost.mts"
const floci = await builder.addFlociAws('floci');
await floci.withConfigFile('./floci.yml');
```

Example `floci.yml` that enables debug logging and disables signature validation:

```yaml title="floci.yml"
floci:
  auth:
    validate-signatures: false
quarkus:
  log:
    level: DEBUG
```

All Floci settings can also be set via `FLOCI_`-prefixed environment variables — `WithConfigFile`/`withConfigFile` is only needed for settings that don't have a dedicated extension method.

### Configure TLS for AWS and Azure

The AWS and Azure emulators serve HTTP and HTTPS on the same port. Configure a certificate with Aspire's certificate APIs and the integration maps the provisioned certificate paths to the matching Floci settings:

**Caution:** The HTTPS endpoint APIs are experimental. The C# example suppresses
  [`ASPIRECERTIFICATES001`](/diagnostics/aspirecertificates001/) around those
  calls.

```csharp title="AppHost.cs"
#pragma warning disable ASPIRECERTIFICATES001

var aws = builder.AddFlociAws("floci-aws")
    .WithHttpsDeveloperCertificate();

var azure = builder.AddFlociAzure("floci-az")
    .WithHttpsDeveloperCertificate();

#pragma warning restore ASPIRECERTIFICATES001

builder.AddProject<Projects.Api>("api")
    .WithReference(aws)
    .WithReference(azure);
```

```typescript title="apphost.mts"
const aws = await builder.addFlociAws('floci-aws');
await aws.withHttpsDeveloperCertificate();

const azure = await builder.addFlociAzure('floci-az');
await azure.withHttpsDeveloperCertificate();

const api = await builder.addProject('api', '../Api/Api.csproj');
await api.withFlociAwsReference(aws);
await api.withFlociAzureReference(azure);
```

Host-process dependents can validate a trusted development certificate without extra client configuration. For container dependents, use `WithDeveloperCertificateTrust(true)` in C# or `withDeveloperCertificateTrust(true)` in TypeScript to install the trust bundle.

**Note:** Plain HTTP remains the default until you explicitly configure a certificate.
  The Floci UI continues to use HTTP over the container network, and the GCP
  emulator doesn't expose an HTTPS listener.

### Connection string / endpoint properties

Available on all three cloud resource types:

```csharp title="AppHost.cs"
var endpoint = floci.PrimaryEndpoint;
var host = floci.Host;
var port = floci.Port;
var connectionString = floci.ConnectionStringExpression;
```

```typescript title="apphost.mts"
const endpoint = await floci.primaryEndpoint();
const host = await floci.host();
const port = await floci.port();
const connectionString = await floci.connectionStringExpression();
```

`connectionStringExpression` is an unresolved endpoint expression. Aspire resolves it for the network used by the dependent resource.

### Endpoint resolution

Every endpoint-bearing environment variable injected by the integration carries an Aspire endpoint expression rather than a hard-coded address:

| Dependent resource    | Resolved address                                            |
| --------------------- | ----------------------------------------------------------- |
| Project or executable | `localhost:{hostPort}`                                      |
| Sibling container     | `{flociResourceName}:{targetPort}` on the container network |

The scheme is `http` unless you [configure a certificate](#configure-tls-for-aws-and-azure), in which case AWS and Azure use `https` on the same port.

## Environment variables

When an app resource references Floci using `WithReference` in C# or a cloud-specific `withFloci*Reference` method in TypeScript, the integration injects the following environment variables:

### AWS

| Variable                    | Value                                                               |
| --------------------------- | ------------------------------------------------------------------- |
| `ConnectionStrings__{name}` | Emulator URL resolved for the dependent resource                    |
| `AWS_ENDPOINT_URL`          | Emulator URL resolved for the dependent resource                    |
| `AWS_DEFAULT_REGION`        | Region passed to `AddFlociAws`/`addFlociAws` (default: `us-east-1`) |
| `AWS_ACCESS_KEY_ID`         | `test`                                                              |
| `AWS_SECRET_ACCESS_KEY`     | `test`                                                              |

### Azure

| Variable                          | Value                                                                                                                                                                |
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ConnectionStrings__{name}`       | Emulator URL resolved for the dependent resource                                                                                                                     |
| `AZURE_STORAGE_CONNECTION_STRING` | Development storage connection string with Blob, Queue, and Table endpoints resolved for the dependent resource, using the well-known `devstoreaccount1` credentials |

### GCP

| Variable                       | Value                                                                      |
| ------------------------------ | -------------------------------------------------------------------------- |
| `ConnectionStrings__{name}`    | Emulator URL resolved for the dependent resource                           |
| `PUBSUB_EMULATOR_HOST`         | Emulator host and port resolved for the dependent resource                 |
| `FIRESTORE_EMULATOR_HOST`      | Emulator host and port resolved for the dependent resource                 |
| `DATASTORE_EMULATOR_HOST`      | Emulator host and port resolved for the dependent resource                 |
| `STORAGE_EMULATOR_HOST`        | Full emulator URL resolved for the dependent resource                      |
| `SECRET_MANAGER_EMULATOR_HOST` | Emulator host and port resolved for the dependent resource                 |
| `GOOGLE_CLOUD_PROJECT`         | Project ID passed to `AddFlociGcp`/`addFlociGcp` (default: `floci-local`)  |
| `CLOUDSDK_CORE_PROJECT`        | Same project ID, for tools that read the `gcloud` CLI's config var instead |

You can override any of these settings via standard Aspire environment variable configuration. All Floci-specific settings can also be set via `FLOCI_`-prefixed environment variables.

## Integration testing

Floci is ideal for integration testing cloud-dependent code without requiring real cloud credentials or incurring costs. Since each Floci resource is managed as a standard Aspire resource, you can use it in integration tests the same way you use other Aspire resources.

## Supported services

- **AWS** (`floci/floci`) — 65+ services including S3, DynamoDB, Lambda, EC2, SQS, SNS, Kinesis, RDS, CloudFormation, CloudWatch, IAM, and many more
- **Azure** (`floci/floci-az`) — Blob/Queue/Table Storage, Cosmos DB, Functions, Event Hubs, Service Bus
- **GCP** (`floci/floci-gcp`) — Pub/Sub, Firestore, Datastore, Storage, Secret Manager, Cloud Functions

For a complete list of supported services per cloud, visit the [Floci documentation](https://floci.io).

## Troubleshooting

### Container fails to start

- Ensure Docker is running and has sufficient resources.
- Check that the specified port isn't already in use.
- Verify the Floci container image is available locally or can be pulled from Docker Hub.

### Connection refused errors

- Verify the Floci container is running: `docker ps | grep floci`
- Check that the endpoint URL matches the configured port.
- Ensure the app resource has the correct `WithReference` or cloud-specific `withFloci*Reference` call.

### Data persistence issues

- Verify the bind mount directory has the correct permissions.
- Check that the host path exists before starting the container.
- Use absolute paths for bind mounts to avoid path resolution issues.

## See also

- [Floci documentation](https://floci.io)
- [Floci GitHub repository](https://github.com/floci-io/floci)
- [Floci UI GitHub repository](https://github.com/floci-io/floci-ui)
- [AWS SDK for .NET](https://docs.aws.amazon.com/sdk-for-net/)
- [Aspire Hosting documentation](/architecture/overview/)
- [CommunityToolkit.Aspire.Hosting.Floci GitHub](https://github.com/CommunityToolkit/Aspire)
- [CommunityToolkit.Aspire.Hosting.Floci NuGet package](https://www.nuget.org/packages/CommunityToolkit.Aspire.Hosting.Floci)