Nanopass: a Scheme framework for building compilers in layers
The new nanopass framework; an embedded DSL for writing compilers in Scheme
At a glance
- What is it?
- The nanopass framework lets you write a compiler as a stack of small, typed languages, each layer defined by a grammar that the framework turns into a parser. It has been the substrate for real production compilers since 2004, and this repository is the R6RS version in Scheme, with ports to Chez, Vicare and Ikarus.
- Who is it for?
- Nanopass fits a language implementer building a compiler incrementally, where the discipline of one small language per layer and a generated parser per grammar is exactly the structure you want, and who is comfortable in Scheme. It does not fit a team that wants a hosted parser generator or a code generator, because the DSL is the tool and the output is tied to the Scheme implementation.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 25 days ago.
- What is it written in?
- Mainly Scheme, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A compiler as a stack of small languages
The repository contains an R6RS version of the Nanopass Compiler Infrastructure, along with the beginnings of a test compiler for the library and the rough start of a users guide. The idea the infrastructure implements is that a compiler can be written as a sequence of small languages, each with its own grammar, and that the work of the compiler is mostly the transitions between those languages. A layer is defined declaratively, the framework generates a parser for it, and the author writes the transformation from one layer to the next. The design separates three things that are usually tangled together: what the source text means, how it is transformed, and what the output looks like. The README lists the files, and the structure of that list is the architecture of the framework itself.
ReadMe.md -- this readme file Acknowledgements -- thanks to those who have supported the work Copyright -- copyright information TODO -- the head of the infinite todo list LOG -- change log for the nanopass framework test-all.ss -- is a simple wrapper for importing the compiler and performing a testing run of all of the tests. nanopass.ss -- the main interface to the nanopass compiler library nanopass/ -- contains the parts that nanopass.ss aggregates tests/ -- contains a testing compiler along with tests for that compiler and a driver for running the tests doc/ -- contains a user guide and developer guide along with a makefile for generating their pdfs with pdflatex
One entry point that aggregates the parts
The layout tells you how the framework is meant to be consumed. nanopass.ss is the main interface to the compiler library, and the nanopass directory holds the parts that it aggregates, which means the implementation is split across files and the public surface is a single unit a user imports. The tests directory contains a testing compiler along with tests for that compiler and a driver for running the tests, and test-all.ss is described as a simple wrapper for importing the compiler and performing a testing run of all of the tests. That last point is worth pausing on. A framework for writing compilers ships with a compiler written in it, and a test driver that runs the whole suite, which means the framework is exercised by the same machinery a user would use. That is a much stronger correctness argument than unit tests of the framework's internals alone, and it explains why a framework that is decades old still works with current Scheme implementations.
Three Scheme implementations, and that is the portability boundary
The framework currently supports Chez Scheme, Vicare Scheme and Ikarus Scheme. That is a short list, and it is the practical constraint on adoption rather than the design. The framework is written in R6RS, the Revised Sixth Report on Scheme, which is a module system and a library standard rather than an implementation, so the portability work is about the parts of R6RS that differ between implementations, which is where a lot of the engineering goes in a project of this kind. The three supported implementations are also three different lineages. Chez is a production Scheme with a strong optimiser, Vicare is a Scheme with its own object system, and Ikarus is a Racket-derived Scheme. If your pipeline already has one of those, the framework drops in. If it has something else, you are porting.
The scholarly lineage behind the framework
The README cites four references, and they explain why the project has the shape it does. The first is the 2013 ICFP paper by Andrew Keep and Robert Dybvig, A Nanopass Compiler for Commercial Compiler Development, which is where the modern form of the framework was presented. The second is Keep's Indiana University doctoral dissertation from the same year, A Nanopass Framework for Commercial Compiler Development, which is the longer treatment. The third is Debasish Sarkar's 2008 dissertation, Nanopass Compiler Infrastructure, the earliest of the line. And the fourth is the 2004 ICFP paper by Sarkar, O. Waddell and Dybvig, A nanopass infrastructure for compiler education, which is the origin story and explains the name. The paper titles carry the point of the whole design. A framework whose purpose is commercial compiler development, and whose first paper was about compiler education, is a tool for building real languages by making each step small enough to be written by one person in one sitting.
Documentation, a changelog, and a todo list that is called infinite
The repository is candid about the state of its own documentation. The doc directory contains a user guide and a developer guide along with a makefile for generating their pdfs with pdflatex, so the guides ship as both sources and a build path for the rendered output. The LOG file is the change log for the framework, which is the file to read if you are tracking behaviour across versions. And the TODO is described in the file listing as the head of the infinite todo list, which is a phrase that tells you a lot about the project's posture. This is a mature research-derived framework that is still being worked on, not a finished product, and the presence of a large todo alongside a long changelog is a healthy combination for a library at this age. The Acknowledgements and Copyright files are present as separate entries, which is conventional for academic-derived software where attribution to prior dissertations matters.
A version line that moves slowly, and a recent bug fix
The release history is a reminder of the timescale. Version 1.9.4 came in April 2026 with a bug fix for nano-syntax-dispatch, and 1.9.3 in August 2025 with small fixes to the generated parser and slightly improved error messages. Before that, 1.9.2 landed in October 2020, with the note that parsers no longer create a run-time dependency. That last change is the one with architectural weight. If the generated parser does not depend on the framework at run time, then a language built with nanopass can be shipped without the framework, which is what makes the framework usable for a language you intend to distribute. The gap between 2020 and 2025 is five years for a patch release, which tells you the project is in maintenance mode with occasional targeted fixes rather than a churn of features. The last push was on 2026-09-28 and the licence is MIT, so the code is yours to use and to embed.
Editorial conclusion
Nanopass fits a language implementer building a compiler incrementally, where the discipline of one small language per layer and a generated parser per grammar is exactly the structure you want, and who is comfortable in Scheme. It does not fit a team that wants a hosted parser generator or a code generator, because the DSL is the tool and the output is tied to the Scheme implementation. Verify first which of the three supported Schemes your build pipeline already has, since the ports are the portability boundary, and read the user guide in the doc directory before designing a language hierarchy, because the layering rules are where the framework imposes its discipline.
Frequently asked questions
What is the Nanopass framework?
It is a Scheme framework for writing compilers, described in the README as an R6RS version of the Nanopass Compiler Infrastructure, along with the beginnings of a test compiler for the library and the rough start of a users guide. It lets you define a compiler as a stack of small languages with a generated parser for each.
Which Scheme implementations does Nanopass support?
The README states that the framework currently supports Chez Scheme, Vicare Scheme and Ikarus Scheme. The implementation is written in R6RS, so the supported implementations are the portability boundary for the project.
What is included in the repository besides the framework itself?
The beginning of a test compiler for the library, tests for that compiler with a driver for running them, a user guide and a developer guide in the doc directory with a makefile for generating their pdfs with pdflatex, a LOG change log, an Acknowledgements file, a Copyright file, and a TODO described as the head of the infinite todo list.
What is the academic background of the Nanopass framework?
The README cites four references: a 2013 ICFP paper by Keep and Dybvig on a nanopass compiler for commercial compiler development, Keep's 2013 Indiana University dissertation on the framework, Sarkar's 2008 dissertation on the compiler infrastructure, and the 2004 ICFP paper by Sarkar, Waddell and Dybvig on a nanopass infrastructure for compiler education.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nanopass-nanopass-framework-scheme)Was this useful?