Software Development

Why I Switched to Janet Lisp: 5 Problems It Solved (2025)

Tired of bloated runtimes and complex embedding? Discover how Janet Lisp, a modern functional language, solved 5 key development problems for me in 2025.

A

Alexei Petrov

Systems programmer and language enthusiast with a passion for simple, elegant solutions.

7 min read3 views

Introduction: The Search for a Better Scripting Language

For years, my development toolkit felt complete, yet cumbersome. For scripting and automation, I'd reach for Python. For web-facing APIs, it was often Node.js. For embedding, Lua was the go-to choice. Each is a powerhouse in its own right, but they all came with baggage. Python brought virtual environments and dependency headaches. Node.js introduced the infamous node_modules black hole. Lua, while beautifully simple to embed, sometimes felt archaic and lacked a robust standard library.

I was stuck in a loop of trade-offs, accepting complexity as a necessary evil for getting the job done. I craved a language that was small, fast, modern, and a joy to use—a language that could be a trusty sidekick for shell scripting, a powerful engine inside a larger C/C++ application, and a pleasant environment for building standalone tools. In 2025, after years of searching, I found my answer: Janet Lisp.

This isn't just another "new shiny language" post. This is the story of how switching to Janet solved five persistent, frustrating problems that had plagued my workflow for over a decade.

What is Janet Lisp, Anyway?

Before we dive into the problems it solves, let's briefly introduce the hero of our story. Janet is a modern, functional, and imperative programming language from the Lisp family. Don't let the word "Lisp" scare you. It’s designed with pragmatism and approachability at its core. Key features include:

  • Minimalist Core: The entire language, including the compiler, interpreter, and core library, compiles to a single, small executable (often under 1MB).
  • First-Class Concurrency: It has built-in support for lightweight cooperative threads called fibers, making concurrent programming remarkably straightforward.
  • Excellent C Interop: Janet was designed from the ground up to be easily embedded in C/C++ applications, with a simple and clean API.
  • Mutable and Immutable Data Structures: It provides a practical mix of data structures, allowing you to choose the right tool for the job without dogmatic purity.
  • Powerful Metaprogramming: Like all Lisps, it treats code as data, enabling powerful macros that can extend the language and eliminate boilerplate.

Think of it as having the embeddability of Lua, the functional power of a Lisp, and the practical, batteries-included feel of Python, all in a tiny, self-contained package.

5 Development Problems Janet Lisp Solved for Me

Switching languages is a big decision. For me, the justification came from how effectively Janet addressed these five core issues.

Problem 1: Dependency Hell and Bloated Deployments

The Pain: Anyone who has tried to deploy a "simple" Python script knows the pain. You need to ensure the target machine has the right Python version, create a virtual environment, pip install -r requirements.txt, and hope there are no system-level library conflicts. The result is a simple script that requires a multi-megabyte environment to run. JavaScript is no better, where a small CLI tool can pull in hundreds of megabytes of dependencies in node_modules.

The Janet Solution: Janet applications are different. The interpreter is a single, static binary. For most scripts, deployment is as simple as copying that one binary and your .janet source file. Need to bundle everything into one executable? Janet's ecosystem has tools for that, creating a self-contained binary you can airdrop onto any compatible system. No runtimes to install, no virtual environments to manage. Just a single file. This is revolutionary for building CLI tools and utilities.

Problem 2: The High Cost of Embedding

The Pain: I often work on larger systems (e.g., in C++ or Rust) that need a scripting layer for plugins or user configuration. Embedding Python is a heavyweight operation, pulling in a massive library and requiring careful management of the Global Interpreter Lock (GIL). Embedding Lua is much easier, but its API, while powerful, can feel very C-centric and verbose.

The Janet Solution: Janet was born to be embedded. Its C API is minimal, elegant, and incredibly easy to grasp. You can initialize a Janet VM, load and run code, and pass data back and forth between C and Janet with just a few lines of code. The data structures map cleanly to C concepts, and the official documentation provides clear, concise examples. It hits the sweet spot between Lua's embeddability and the modern features I wanted in a scripting language.

Problem 3: Making Concurrency Sane Again with Fibers

The Pain: Modern applications need concurrency. Traditional OS threads are heavy and prone to race conditions. Callback-based models (like in early Node.js) lead to unreadable "callback hell." Even modern async/await syntax can add significant cognitive overhead and complexity.

The Janet Solution: Janet's built-in fibers are a game-changer. Fibers are lightweight threads managed by the Janet VM, not the OS. You can spawn thousands of them without breaking a sweat. The model is cooperative, which sidesteps many of the race condition issues found in preemptive threading. The syntax is beautifully simple:

(ev/go (print "Hello from a fiber!"))
(ev/go (do (os/sleep 1) (print "This runs after a 1-second delay")))
# ... main program continues immediately ...

This makes it trivial to write non-blocking I/O operations, manage multiple network clients, or run background tasks without contorting your code's logic.

Problem 4: The Lost Art of Interactive Development

The Pain: My development loop often looked like this: write code, save, switch to terminal, run tests/application, see error, switch back to editor, repeat. While some languages have a REPL (Read-Eval-Print Loop), they often feel disconnected from the main development process. They are a tool for trying things out, not for building the application itself.

The Janet Solution: Janet, like its Lisp cousins, embraces REPL-driven development. You build your application interactively. You connect your editor to a running Janet process, sending code to be evaluated in real-time. You can redefine functions, inspect data, and modify the program's state while it's running. This tight feedback loop is incredibly productive and feels less like writing code and more like sculpting a live system. It brought the joy and discovery back into my programming sessions.

Problem 5: A Practical Bridge to Functional Programming

The Pain: I've always been intrigued by the power of functional programming (FP)—immutability, pure functions, higher-order functions. However, diving into languages like Haskell or even Clojure felt like a steep, academic climb. They were powerful, but the learning curve and dogmatic approach were often a barrier to using them for my day-to-day scripting tasks.

The Janet Solution: Janet offers a gentle on-ramp to the Lisp and FP worlds. Its syntax is clean and simple Lisp. It encourages a functional style but doesn't force it. You have access to immutable data structures (tuples, structs) but can also use mutable ones (arrays, tables) when it makes practical sense. It lets you taste the power of macros and functional composition without demanding you rewrite your entire mental model of programming overnight. It's a pragmatic language that values results over purity.

Janet vs. The Usual Suspects: A Quick Comparison

Feature Comparison: Janet vs. Python & Lua (2025)
Feature Janet Lisp Python Lua
Binary Size Very Small (< 1MB) Large (25MB+ runtime) Very Small (< 300KB)
Deployment Single binary, trivial Complex (venv, dependencies) Single binary, trivial
Concurrency Model Built-in Fibers (Cooperative) Threads (GIL) & asyncio Coroutines (via libraries)
Embedding API Excellent, modern, simple Complex, heavyweight Excellent, C-style, minimal
Paradigm Functional & Imperative Object-Oriented & Imperative Imperative & Procedural
Standard Library Moderate, well-curated Massive, "batteries-included" Minimal, requires external libs

Is Janet Right for Your Next Project?

Janet isn't a silver bullet that will replace every other language. If you're doing data science, the Python ecosystem is unbeatable. If you're building a massive enterprise web application, the frameworks in Java or C# might be a better fit.

However, Janet excels in a surprisingly wide range of domains:

  • CLI Tools: Its small size and easy deployment make it a perfect choice.
  • Scripting & Automation: A fantastic, modern replacement for shell scripts or simple Python scripts.
  • Game Development: Its embeddability and performance make it a strong contender for a scripting engine.
  • Embedded Systems: Where resources are tight, Janet's small footprint is a huge advantage.
  • Network Services: Built-in fibers make it easy to write high-performance, concurrent network applications.

If you're a developer who values simplicity, efficiency, and a joyful, interactive development process, I urge you to give Janet a try. It solved years of nagging problems for me and has become the most versatile and enjoyable tool in my arsenal.