> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fjall.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Pattern

> Build your own AWS infrastructure with Fjall by picking individual resources on a blank canvas.

## Overview

The Custom pattern starts your application as a blank canvas. Instead of a preset tier, you choose a network configuration, then add each compute, database, and storage resource yourself with `fjall add`.

```bash theme={null}
fjall create app --type custom
```

Use Custom when no preset tier fits, when you are learning how Fjall composes resources, or when you need full control over the architecture.

## Prerequisites

| Requirement | Detail                                      |
| ----------- | ------------------------------------------- |
| Fjall CLI   | Installed and authenticated (`fjall login`) |
| Node.js     | Version 22 or later                         |
| AWS account | Connected via `fjall connect`               |

## Interactive Flow

A Custom application is created in three short steps, then you add resources afterwards.

```bash theme={null}
? Choose your starting point? Custom
? Name your application? api
? Network configuration?
  > Standard      Production ready · 2 AZs, 1 NAT Gateway, KMS
    Lightweight   Cost effective · 2 AZs, shared NAT
    Resilient     High availability · 3 AZs, 3 NAT Gateways, CMK Keys
    Tinkerer      Free tier · 2 AZs, no NAT Gateway
    No network    Standalone resources · S3, CDN, Lambda, EventBridge
```

The review then confirms a blank canvas:

```bash theme={null}
Resources: Blank canvas (add resources after creation)
```

A Custom application does not prompt for compute, database, or storage during creation. Pick a network preset (or `No network` for standalone resources), confirm, then add resources with `fjall add`.

## Adding Resources

Add each resource to the generated `infrastructure.ts` with `fjall add <type> --name <PascalCaseName>`. The `--name` is required and PascalCase.

```bash theme={null}
# Add an ECS service
fjall add compute --name Api --type ecs

# Add a database (variant is the --type property)
fjall add database --name UserDb --type Aurora

# Add an S3 bucket
fjall add storage --name Uploads
```

Valid resource types: `database`, `storage`, `compute`, `messaging`, `cdn`, `network`, `pattern`, `vpc-peer`, `vpc-peer-accepter`, `cross-plan-connection`.

Database variant is a property, not part of the type. Pass `--type <variant>` where the variant is one of `Aurora`, `Instance`, `GlobalAurora`, `ClickHouse`, or `DynamoDB`.

## Building Custom Architectures

Each `fjall add` writes a factory call into `infrastructure.ts`. The examples below show the generated code for common architectures so you can see what each combination produces.

### Microservices Architecture

```typescript theme={null}
import {
  App,
  ComputeFactory,
  DatabaseFactory,
} from "@fjall/components-infrastructure";
import { Code, FunctionUrlAuthType } from "aws-cdk-lib/aws-lambda";

const app = App.getApp("microservices");

// API gateway
const apiGateway = app.addCompute(
  ComputeFactory.build("ApiGateway", {
    type: "lambda",
    deployment: "code",
    code: Code.fromAsset("lambda/api-gateway"),
    handler: "index.handler",
    functionUrl: { authType: FunctionUrlAuthType.NONE },
  }),
);

// User service
const userDb = app.addDatabase(
  DatabaseFactory.build("UserDb", {
    type: "Aurora",
    databaseName: "Users",
  }),
);

const userService = app.addCompute(
  ComputeFactory.build("UserService", {
    type: "ecs",
    services: [
      {
        name: "user",
        capacityProvider: "FARGATE",
        containers: [{ port: 3001 }],
      },
    ],
  }),
);

// Order service
const orderDb = app.addDatabase(
  DatabaseFactory.build("OrderDb", {
    type: "Instance",
    databaseName: "Orders",
  }),
);

const orderService = app.addCompute(
  ComputeFactory.build("OrderService", {
    type: "ecs",
    services: [
      {
        name: "order",
        capacityProvider: "FARGATE",
        containers: [{ port: 3002 }],
      },
    ],
  }),
);
```

### Event-Driven Architecture

```typescript theme={null}
// Event processor
const eventProcessor = app.addCompute(
  ComputeFactory.build("EventProcessor", {
    type: "lambda",
    deployment: "code",
    code: Code.fromAsset("lambda/processor"),
    handler: "index.handler",
    memorySize: 1024,
    timeout: 300,
  }),
);

// Event store
const eventStore = app.addDatabase(
  DatabaseFactory.build("EventStore", {
    type: "Aurora",
    databaseName: "Events",
  }),
);

// API layer
const api = app.addCompute(
  ComputeFactory.build("Api", {
    type: "ecs",
    services: [
      {
        name: "api",
        capacityProvider: "FARGATE",
        containers: [{ port: 3000 }],
      },
    ],
  }),
);
```

### Batch Processing

```typescript theme={null}
// Job queue database
const jobDb = app.addDatabase(
  DatabaseFactory.build("JobDb", {
    type: "Instance",
    databaseName: "JobQueue",
    instanceType: "t4g.micro", // Free tier eligible
  }),
);

// Batch processor
const batchProcessor = app.addCompute(
  ComputeFactory.build("BatchProcessor", {
    type: "ecs",
    services: [
      {
        name: "batch",
        capacityProvider: "FARGATE_SPOT", // Cost-optimised
        cpu: 2048,
        memoryLimitMiB: 4096,
        containers: [{ port: 8080 }],
      },
    ],
  }),
);

// Scheduler
const scheduler = app.addCompute(
  ComputeFactory.build("Scheduler", {
    type: "lambda",
    deployment: "code",
    code: Code.fromAsset("lambda/scheduler"),
    handler: "index.handler",
  }),
);
```

### Hybrid Architecture

```typescript theme={null}
// Legacy system connector
const legacyConnector = app.addCompute(
  ComputeFactory.build("LegacyConnector", {
    type: "ec2",
    instanceType: "t4g.large",
    ssh: {},
  }),
);

// Modern API
const modernApi = app.addCompute(
  ComputeFactory.build("ModernApi", {
    type: "lambda",
    deployment: "code",
    code: Code.fromAsset("lambda/api"),
    handler: "index.handler",
    environment: {
      LEGACY_ENDPOINT: "10.0.1.100",
    },
  }),
);

// Shared database
const sharedDb = app.addDatabase(
  DatabaseFactory.build("SharedDb", {
    type: "Instance",
    databaseName: "Shared",
  }),
);
```

### Mix and Match Resources

The Custom pattern supports any combination of compute and database types.

```typescript theme={null}
// Mix compute types
const lambda = app.addCompute(
  ComputeFactory.build("Lambda", {
    type: "lambda",
    deployment: "code",
    handler: "index.handler",
  }),
);
const ecs = app.addCompute(
  ComputeFactory.build("Ecs", {
    type: "ecs",
    services: [
      {
        name: "app",
        capacityProvider: "FARGATE",
        containers: [{ port: 3000 }],
      },
    ],
  }),
);
const ec2 = app.addCompute(
  ComputeFactory.build("Ec2", { type: "ec2", instanceType: "t4g.micro" }),
);

// Mix database types
const aurora = app.addDatabase(
  DatabaseFactory.build("Aurora", { type: "Aurora", databaseName: "app" }),
);
const instance = app.addDatabase(
  DatabaseFactory.build("Instance", { type: "Instance", databaseName: "app" }),
);
const freeTier = app.addDatabase(
  DatabaseFactory.build("FreeTierDb", {
    type: "Instance",
    databaseName: "app",
    instanceType: "t4g.micro",
  }),
);
```

## When to Use

**Choose Custom for:**

* Unique architectural requirements
* Proof of concepts
* Learning how Fjall composes resources
* Maximum control over every resource

**Choose a preset tier for:**

* Standard architectures (Standard or Resilient)
* Quick deployment with opinionated defaults
* Free experimentation (Tinkerer)

## Tips

* Plan your architecture before adding resources.
* Start with one compute resource and add more incrementally.
* Use PascalCase names that describe each resource (`Api`, `UserDb`, `Uploads`).
* Match resource types to cost targets (`t4g.micro` instances and `FARGATE_SPOT` for low-cost workloads).

## Common Custom Architectures

| Architecture      | Resources to add                                                                                   |
| ----------------- | -------------------------------------------------------------------------------------------------- |
| API + worker      | `compute` Api (ECS Fargate), `compute` Worker (ECS Fargate Spot), `database` SharedDb (Aurora)     |
| Static site + API | `compute` Web (Lambda with function URL), `compute` Api (ECS Fargate), `database` AppDb (Instance) |
| Data pipeline     | `compute` Ingest (Lambda), `compute` Process (ECS Fargate Spot), `database` Store (Aurora)         |

## Next Steps

<CardGroup cols={2}>
  <Card title="Compute Factory" icon="server" href="/patterns/compute-factory">
    ECS, Lambda, and EC2 options for compute resources.
  </Card>

  <Card title="Database Factory" icon="database" href="/patterns/database-factory">
    Aurora, Instance, DynamoDB, and ClickHouse variants.
  </Card>

  <Card title="Storage Factory" icon="box" href="/patterns/storage-factory">
    Add S3 buckets to your application.
  </Card>

  <Card title="Deploy Application" icon="rocket" href="/deployment/deploy-application">
    Ship your custom architecture to AWS.
  </Card>
</CardGroup>
