# Sceptre: driving CloudFormation from a directory of YAML files

> Sceptre is a Python tool that turns AWS CloudFormation into a directory of stack configuration files, resolving stack dependencies, grouping related stacks and running parallel builds without asking you to keep state. The trade is that it is an organisational layer over CloudFormation rather than a replacement for it.

**Sceptre/sceptre** — Build better AWS infrastructure

- Repository: https://github.com/Sceptre/sceptre
- Website: https://docs.sceptre-project.org
- Stars: 1,534 · Forks: 301
- Language: Python
- License: NOASSERTION
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/sceptre-sceptre

## What Sceptre does, and what it deliberately does not do

Sceptre is a tool to drive AWS CloudFormation. It automates the mundane, repetitive and error-prone tasks, enabling you to concentrate on building better infrastructure, and the repository description sums it up as Build better AWS infrastructure.

What that means concretely is that Sceptre does not implement a provisioning engine. CloudFormation remains the engine, and Sceptre is a driver in front of it. The benefits list makes the point explicitly: it utilises cloud-native Infrastructure as Code engines (CloudFormation), and you do not need to manage state.

That last clause is the design decision that shapes everything else. Tools that maintain their own state, a Terraform-style state file, or an internal database of what exists, take on the obligation to keep that state consistent with reality, and the failure mode when it drifts is that your infrastructure and your model of it disagree. Sceptre has no such file, because CloudFormation already knows what exists, and Sceptre asks CloudFormation.

The rest of the benefits list is about what Python and YAML give you instead. Simple templates using popular templating syntax, Yaml and Jinja. Powerful flexibility using a mature programming language, Python. Easy to integrate as part of a CI/CD pipeline by using Hooks. A simple CLI and API. And unopinionated, Sceptre does not force a specific project structure, which is a deliberate statement that your directory layout is your business.

The audience is a platform or infrastructure team that has outgrown a single large CloudFormation template. Sceptre is for the case where you have thirty stacks rather than one, where some of them depend on outputs of others, and where you deploy the same set of stacks to several accounts and regions. The primary language is Python, the documentation is at docs.sceptre-project.org, the package is on PyPI as sceptre, and the version in pyproject.toml is 4.7.0 with a Development Status of 5, Production/Stable.

## Stack Groups, and how the directory becomes a deployment

The example in the README is the clearest explanation of the model, and it is worth reading closely because the directory layout is the API.

Sceptre organises Stacks into Stack Groups. Each Stack is represented by a YAML configuration file stored in a directory which represents the Stack Group. The example has two Stacks, vpc and subnets, in a Stack Group named dev:

```sh
$ tree
.
├── config
│   └── dev
│      ├── config.yaml
│      ├── subnets.yaml
│      └── vpc.yaml
└── templates
    ├── subnets.py
    └── vpc.py
```

So a directory is an environment, a file is a stack, and the stack group is also the unit of command. The create command takes a path:

```sh
$ sceptre create dev/vpc.yaml
```

and a group-level command operates on the whole directory:

```sh
$ sceptre delete dev
```

which in the example deletes the subnet before the VPC, in the right order, automatically. The README's note on that behaviour is precise and worth knowing before you run it: deleting Stacks will only delete a given Stack, or the Stacks that are directly in a given StackGroup, and by default Stack dependencies that are external to the StackGroup are not deleted.

That last sentence is a safety property rather than a limitation of the implementation. If a stack in dev depends on something in shared, deleting dev will not take the shared stack with it. The behaviour is the opposite of what some tools do, and it is the right default.

The structure scales to a second dimension. The cross Stack Group example has config/dev/ with network, users and compute subdirectories, a config/staging/eu directory, a hooks/ directory holding stack.py, a templates/ directory and a vars/ directory with per-environment variable files. In that project staging/eu/stack.yaml has a dependency on the output of dev/users/iam.yaml, and if you asked to create staging/eu/stack.yaml, Sceptre resolves all of its dependencies, including dev/users/iam.yaml, before attempting to create the stack.

So the unit of deployment is not the file you name on the command line, it is the transitive closure of what that file needs. That is the whole value proposition, and it is why the tool has a dependency resolver at all.

## Resolvers and hooks, the two extension points

Two plugin mechanisms carry most of the flexibility, and the pyproject.toml lists them in full.

Resolvers insert dynamic values into templates. The registered set is: environment_variable, file_contents, stack_output, stack_output_external, no_value, select, stack_attr, sub, split and join.

That list describes the shape of the thing. A resolver turns a value in your stack configuration into something the template can use, and the ten of them cover the cases that come up in practice. stack_output reads an output of another stack in the same run, and stack_output_external reads an output of a stack outside it, which is how you point a stack at a network someone else owns. file_contents pulls in the body of a file, environment_variable takes a value from the process environment, select picks between values by a condition, stack_attr reads an attribute of the stack itself, and sub, split and join are string operations. no_value is there to deliberately supply nothing.

Hooks run arbitrary code before and after stack builds. The registered hooks are asg_scheduled_actions, asg_scaling_processes and cmd. The two asg ones are about Auto Scaling groups, and cmd is a general shell command. The README describes the purpose of hooks as support for running arbitrary code as Hooks before/after Stack builds, and the Benefits list puts it as easy to integrate as part of a CI/CD pipeline by using Hooks.

The mechanism is a Poetry entry point group, sceptre.hooks, so a hook is a Python class registered by name and loaded at runtime. The same pattern is used for the resolvers in the sceptre.resolvers group, and for a third group, sceptre.template_handlers, which has three entries: file, s3 and http. That last one is what lets a template live in a local file, in an S3 bucket, or behind an HTTP URL, without the stack configuration changing.

The template handlers group also explains the template format support. Templates can be written in JSON, YAML, Jinja2 or Python DSLs such as Troposphere, and the file and s3 and http handlers cover where the template body comes from. The Jinja2 support is the interesting one for a team that already has a templating habit, because it means the CloudFormation template is rendered with Jinja before it is submitted, with Sceptre's resolvers available as functions inside it.

## Installing it, and running it in a container

There are two install routes, and the container one is spelled out in more detail than most projects bother with.

From PyPI:

```console
$ pip install sceptre
```

The Installation Guide at docs.sceptre-project.org/latest/docs/install.html has the rest, and the PyPI badges show the supported Python versions, with pyproject.toml requiring python = ^3.10.

The Docker route has been available from version 2.0.0 onward, and the images live in the sceptreorg repository on Docker Hub. The steps are a pull, with the version number or latest:

```console
docker pull sceptreorg/sceptre:2.5.0
```

Then a run, and the two volume mounts are the part that matters. You mount the working directory where your project resides to a directory called project, and you mount a volume with your AWS config to the container:

```console
docker run -v $(pwd):/project -v /Users/me/.aws/:/root/.aws/:ro sceptreorg/sceptre:latest --help
```

The AWS config mount is read-only, which is the correct arrangement, and the project mount is the working directory so the config and templates directories are visible where Sceptre expects them.

There is a variant for getting a shell, and it is the one to use for development:

```console
docker run -ti --entrypoint='' sceptreorg/sceptre:latest sh
```

which enters the container shell where you can execute sceptre commands directly. The README explains that if you have other environment variables in your non-docker shell, you will need to pass these in on the Docker CLI using the -e flag.

The Dockerfile itself is minimal and shows what the image really needs. It is python:3.10-alpine, installs bash, copies the package metadata and the sceptre/ directory, installs wheel and then the package with pip, sets the working directory to /project, and uses ENTRYPOINT ["sceptre"]. So the image is the package plus its dependencies and nothing else, which is what you want for a tool that mostly makes AWS API calls.

The remaining repository structure tells you about the project's engineering. There is a Dockerfile, a .pre-commit-config.yaml, a .yamllint, a .flake8, a tox.ini, a behave.ini, integration-tests/ and tests/ directories, a docs/ directory, a sponsors/ directory, and .kiro/ for editor or agent configuration. The presence of behave and a separate integration-tests directory suggests the integration tests are written as behaviour scenarios rather than unit tests, which is the right shape for a tool whose correctness is about sequences of AWS API calls.

## Meta-operations, and the visibility argument

One feature deserves separate attention because it is the one that is not about creating anything.

Sceptre implements meta-operations, which allow you to find out information about your Stacks. The example lists the resources in a stack and, interestingly, in a related one:

```sh
$ sceptre list resources dev/subnets.yaml

- LogicalResourceId: Subnet
  PhysicalResourceId: subnet-445e6e32
  dev/vpc:
- LogicalResourceId: VirtualPrivateCloud
  PhysicalResourceId: vpc-c4715da0
```

The output shows the logical and physical resource identifiers, and it groups them under the stack they came from, including a stack other than the one named on the command line. The logical identifier is the one in your template and the physical one is what AWS assigned, and being able to see both is the point: after a create, the physical IDs are the values you need to feed into other systems, and this gets them out of CloudFormation without you opening the console.

The features list calls this infrastructure visibility with meta-operations such as Stack querying protection. The word protection is doing work: these are read operations that do not modify anything, and being able to query without fear of a side effect is what makes them safe to run against a live account.

The other features in the list that matter for a real deployment are the ones about scale and reach. Fast, highly parallelised builds, because Sceptre has to talk to the CloudFormation API for every stack and a serial loop over thirty stacks is slow. Built in support for working with Stacks in multiple AWS accounts and regions, which is the situation almost every organisation above a certain size is in. And Stack Group support by bundling related Stacks into logical groups, with Stack Group-level commands such as creating multiple Stacks with a single command.

Together those make Sceptre a tool for the multi-account, multi-environment case rather than for a single template, and the parallel builds and cross-account support are what separate it from running the AWS CLI by hand.

## Where Sceptre is the wrong tool

There are three limits, and the first one is about what CloudFormation itself can and cannot do.

The first is that Sceptre inherits CloudFormation's limits exactly. CloudFormation has a hard per-account stack limit, it has a template size limit, and it does not support every resource type or every feature that the AWS console does. Sceptre will organise those stacks beautifully and then hit the same ceiling. A tool that promises to let you build better infrastructure is not going to make an impossible API call possible, and anyone adopting Sceptre should be clear that they are still inside CloudFormation's constraints.

The second is that Sceptre is not a state machine, and that cuts both ways. Because there is no state file, there is nothing to drift, and there is no separate thing to keep in sync with reality. But it also means there is no record of what you intended, and no diff of what you changed between runs, other than what CloudFormation itself reports. If your requirement is an auditable history of configuration changes, that history lives in the stack events and in your own version control, not in Sceptre.

The third is the plugin surface, and it is the one to check before committing. Resolvers and hooks are Python entry points, so they are powerful, and they are also code you write and run inside the deployment path, alongside and with the same privileges as the tool itself. There is no sandboxing described. A hook that runs arbitrary code before a stack build is a hook that can do anything the credentials allow, and the cmd hook in particular is a shell command. That is the right design for a tool that is already running with your AWS credentials, but it does mean the plugin set is part of your security boundary and needs the same review as the rest of your infrastructure code.

There is a fourth, more mundane point. The Docker examples in the README reference version 2.5.0, while the current version in pyproject.toml is 4.7.0, so the documentation examples lag the current release. Anyone copying the Docker command should check the tag against the current version rather than assuming the example is current.

## Conclusion

Adopt Sceptre if you already use CloudFormation and want your stacks organised as files with dependency resolution, environment variables and cross-account support rather than as a monolith template. Do not adopt it if you want a different provisioning model, since Sceptre deliberately does not keep its own state and does not replace CloudFormation's capabilities. Verify first that your template style is one of the supported ones, JSON, YAML, Jinja2 or a Python DSL such as Troposphere, that the regions and accounts you deploy into are configured the way your organisation expects, and that the hooks and resolvers you rely on are available in the version you install.

## FAQ

### What is Sceptre and what does it automate?

Sceptre is a tool to drive AWS CloudFormation. It organises stacks into Stack Groups represented by directories of YAML files, resolves dependencies between them by passing stack outputs to dependent parameters, supports multiple AWS accounts and regions, and runs highly parallelised builds, without requiring you to manage state.

### How do I install Sceptre?

From PyPI with `pip install sceptre`, or from the Docker image published as sceptreorg/sceptre, available from version 2.0.0 onward. The Docker run mounts your project directory at /project and your AWS config read-only at /root/.aws, and the image entrypoint is the sceptre command itself.

### What are Sceptre's Resolvers and Hooks?

Resolvers insert dynamic values into templates, and the registered set includes environment_variable, file_contents, stack_output, stack_output_external, no_value, select, stack_attr, sub, split and join. Hooks run arbitrary code before and after stack builds, with asg_scheduled_actions, asg_scaling_processes and cmd registered by default.

### Does deleting a Stack Group in Sceptre delete its dependencies?

Not by default. The README states that deleting Stacks will only delete a given Stack, or the Stacks directly in a given StackGroup, and that Stack dependencies external to the StackGroup are not deleted.

## Sources

- [Issues](https://github.com/Sceptre/sceptre/issues)
- [Project website](https://docs.sceptre-project.org)
- [README](https://github.com/Sceptre/sceptre/blob/master/README.md)
- [Sceptre/sceptre on GitHub](https://github.com/Sceptre/sceptre)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/sceptre-sceptre
