# Torch is a wrapper around phx.gen.html that swaps in its own templates and then cleans up

> A Phoenix admin generator that injects custom templates into your priv/static directory, runs the standard Phoenix HTML generator with the arguments you passed, and then removes the templates so they do not interfere with later generator runs. The upside is a usable admin fast, and the cost is that the generated code is yours to maintain afterwards.

**mojotech/torch** — A rapid admin generator for Elixir & Phoenix

- Repository: https://github.com/mojotech/torch
- Stars: 1,173 · Forks: 84
- Language: Elixir
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/mojotech-torch

## The mechanism is template injection, and the cleanup is the clever part

Torch is a rapid admin generator for Phoenix applications. It creates custom templates and relies on the Phoenix HTML generator under the hood, and the README explains the mechanism in enough detail that the design decision is obvious.

Torch injects its own custom templates into your `priv/static` directory, then runs the `mix phx.gen.html` task with the options you passed in. Finally, it uninstalls the custom templates so they do not interfere with running the plain Phoenix generators.

That last sentence is the part that makes the approach work. The obvious risk of injecting templates into a shared directory is that they linger and quietly change the behaviour of every future generator run in the project. Uninstalling them after each run means the generator is a one-shot operation, and the only lasting artefacts are the generated files themselves.

The consequence is that the `torch.gen.html` task takes all the same arguments as `phx.gen.html` and does some extra configuration on either end. Anyone who knows the Phoenix HTML generator already knows this tool, and the documentation points at `mix help phx.gen.html` for the supported options and format.

That is a well judged design for a tool whose audience is Phoenix developers. Rather than inventing a parallel generator with its own argument language and its own template format, it reuses the upstream one and injects the difference. The cost is that the templates have to live in a location Phoenix recognises, which is why the injection step exists at all.

## Four installation steps, and a version matrix that is not backwards compatible

The install is four steps, and the version requirements are stated before anything else.

Phoenix 1.7 or newer, Elixir 1.15 or newer, and OTP 25 or newer. The README then flags that this version of Torch, 6.x, only supports Phoenix 1.7 and OTP 25 and is not fully backwards-compatible with previous versions, with the details in an UPGRADING file. Older branches are named for the stacks they support: v5.0 for Phoenix 1.7 and OTP 24, v4.0 for Phoenix 1.6, and v3.0 for Phoenix 1.5 and below.

The dependency goes into mix.exs.

```elixir
def deps do
  [
    {:torch, "~> 6.0"}
  ]
end
```

Then you add a `Plug.Static` plug to your endpoint, serving the Torch assets.

```elixir
plug(
  Plug.Static,
  at: "/torch",
  from: {:torch, "priv/static"},
  gzip: true,
  cache_control_for_etags: "public, max-age=86400",
  headers: [{"access-control-allow-origin", "*"}]
)
```

Then the config.

```elixir
config :torch, otp_app: :my_app_name
```

And finally `mix torch.install` to install the assets into your application.

That `otp_app` setting is worth pausing on, because it is what makes Torch work in an umbrella or in a Phoenix app whose OTP application name differs from the default. Torch needs to know which application to write into, and an explicit setting is better than a guess.

The static plug is the part that touches your production configuration. The cache control is set to a day with etags, and the access-control-allow-origin header is a wildcard, which is a deliberate choice for a directory of static assets served to a browser.

## The generated output tells you what you are signing up for

The example output is the most useful part of the README, because it shows exactly what lands in your repository.

The command takes a context module, a schema module, a table name and the column list.

```bash
$ mix torch.gen.html Blog Post posts title:string body:text published_at:datetime published:boolean views:integer
```

What you get is Phoenix HTML generator output plus a test file and a fixtures file injected into the test tree, with the paths reflecting the Phoenix version, `test/phx1_6/blog_test.exs` and `test/support/fixtures/blog_fixtures.ex` in the example. Then the generator prints the two manual steps it cannot do for you: the route to add to the browser scope in the router, and the migration to run.

```elixir
resources "/posts", PostController
```

```bash
$ mix ecto.migrate
```

And it reminds you that the `Plug.Static` plug has to be in your endpoint, and that you can add a link to the Torch layout if you want navigation.

The layout is installed into `my_app_web/templates/layout/torch.html.heex`, and the nav snippet is where you add your own links.

```html
<nav class="torch-nav">
  <a href="/posts">Posts</a>
</nav>
```

The key thing to understand is that all of this is generated code in your repository. Torch is not a runtime dependency that renders an admin. It is a code generator, and after it has run you own the output, including the parts you will want to redesign. That is the right trade for an internal tool, and it is also the reason the admin will eventually drift from what the generator would produce today.

## The no-schema flag is how you add an admin to an existing system

The second use case in the README is the one that matters for a lot of teams, and it is handled by flags rather than by a separate code path.

The problem it solves is that your application already contains the modules and controllers and you just want the Torch admin interface on top of them. Since the `torch.gen` mix tasks are just wrappers around the existing `phx.gen` tasks, you can use most of the same flags, and the example uses `--no-schema` and `--no-context` with a `web Admin` argument.

```bash
$ mix torch.gen.html Blog Post posts --no-schema --no-context --web Admin title:string body:text published_at:datetime published:boolean views:integer
```

The `web Admin` argument is the other half. It names the web module the generated controller belongs to, so the admin pages live under their own namespace rather than being mixed into your main web module.

This is the scenario where a generated admin is most useful, because the data model already exists and is already tested. The work left is the presentation layer, which is exactly the tedious part that a generator can bootstrap.

The wider point is that Torch sits at the intersection of Phoenix conventions rather than beside them. Because it delegates to `phx.gen.html`, the arguments, the file layout, the test file and the fixtures all follow the upstream generator's patterns, and a developer who has run the Phoenix generator before will not be surprised by anything in the output.

## Pagination is a module you can override, and association filters are the known gap

Two areas of the generated code are worth understanding before you generate, because both need decisions.

The first is pagination. By default the Torch generators add a `use Torch.Pagination` line to your context module, with the repo, the model and a name.

```elixir
use Torch.Pagination,
  repo: MyApp.Repo,
  model: MyApp.Blog.Post,
  name: :posts
```

The `Torch.Pagination` module is documented on hexdocs, and it can be customised per model or globally for the whole application. The README is precise about the catch: if you want to customise the pagination functions themselves, do not use the default `Torch.Pagination`, and instead define your own `paginate_*/2` method that returns a `Scrivener.Page` object. You can also define your own pagination system entirely, but that requires further customisation of the generated Torch controllers.

So pagination has a supported middle path and an unsupported escape hatch, and the distinction is worth knowing before you generate for twenty models and then discover you want to change it.

The second area is a stated limitation. Torch does not support association filters at this time, because Filtrex does not yet support them, with links to two issues on the Filtrex repository for the latest status. The README does not stop there, though, and shows how to roll your own with a hand written filter function that joins the association in the query, dropping the association params from the filter map before passing the rest to `Filtrex.query` and applying a separate credential filter.

That example is the more useful half of the section. Association filtering is the kind of admin feature people discover they need after they have generated, and the workaround is a dozen lines in your own context module rather than a fork of the generator.

## Conclusion

Adopt Torch if you are building a Phoenix application and need a working admin interface for a handful of schemas in a day, rather than a hand designed internal tool. Do not adopt it if the admin is a product surface with its own design requirements, because the templates are generated once and then left as ordinary code in your repository. Verify first that your Phoenix and OTP versions are within the supported range, that you understand the generated code is yours to maintain after generation, and that the pagination and filtering behaviour matches what your operators expect from an admin list.

## FAQ

### What are the requirements for Torch?

Phoenix Framework 1.7 or newer, Elixir 1.15 or newer, and OTP 25 or newer. Torch 6.x is not fully backwards compatible with earlier versions, so older stacks need the v5.0, v4.0 or v3.0 branches.

### How do I install Torch in a Phoenix application?

Add {:torch, "~> 6.0"} to your deps in mix.exs and run mix deps.get, add a Plug.Static plug at /torch serving from {:torch, "priv/static"}, set config :torch, otp_app: :my_app_name, then run mix torch.install.

### How does Torch generate the admin pages?

It injects its own templates into your priv/static directory, runs the mix phx.gen.html task with the options you passed, then uninstalls the templates so they do not interfere with later generator runs. The torch.gen.html task takes the same arguments as phx.gen.html.

### Can I use Torch with an existing Phoenix app that already has models and controllers?

Yes. Use the --no-schema and --no-context flags with a web module argument, for example mix torch.gen.html Blog Post posts --no-schema --no-context --web Admin, and Torch will generate only the admin interface on top of the existing modules.

### Does Torch support filtering by association fields?

Not at the moment, because Filtrex does not support it yet, and the README links the two open issues. It does show how to roll your own with a custom filter function that joins the association in the query.

## Sources

- [Issues](https://github.com/mojotech/torch/issues)
- [mojotech/torch on GitHub](https://github.com/mojotech/torch)
- [README](https://github.com/mojotech/torch/blob/master/README.md)
- [Releases](https://github.com/mojotech/torch/releases)

---

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