Computer Science › Compilers & Languages
Domain-Specific Language
A small language built for one problem, like SQL or regex.
Also known as: domain-specific language, DSL, internal DSL
A domain-specific language (DSL) is a small language designed for one problem area rather than general programming. SQL for queries, regular expressions for text patterns, YAML for configuration, a query builder for a reporting tool — each is narrow by design, which makes expressing that domain’s ideas concise and hard to get subtly wrong.
There are two broad kinds:
- External DSLs — have their own syntax and a dedicated parser/interpreter. SQL and regex are external: you write them as text, and a tool understands them.
- Internal (embedded) DSLs — expressed in the host language, using its syntax cleverly (method chaining, operator overloading). A query builder like
users.where(active: true).order(:name)is an internal DSL.
external: SELECT name FROM users WHERE active = true; # its own grammar
internal: users.where(active: true).order(:name) # host language syntax
The pay-off is expressiveness for the target domain and safety for the user: a configuration DSL can validate what a hand-written parser wouldn’t, and a query DSL can prevent injection. The cost is building and maintaining a language.
The classic mistakes:
- Building a DSL when a library would do. DSLs are expensive — grammar, parser, error messages, tooling. If a well-designed API gets you 90% there, prefer it.
- Making it too general. A DSL that grows into a general-purpose language has all the costs and fewer of the benefits; you’ve built a worse programming language.
- Ignoring error messages. The whole value of a dedicated syntax is guidance; a DSL that reports “invalid” without location or context is worse than the library it replaced.
- Overusing internal DSL magic. Clever method-missing or operator tricks can make an internal DSL unreadable and impossible to debug. Clarity first.
- Forgetting security. A DSL that evaluates user input (a query language, a template language) needs careful sandboxing; that’s how injection bugs creep in.
Good DSLs — SQL, regex, CSS, configuration formats — earn their keep because the domain is narrow and repeated. When you build one, treat it as a real language: grammar, parser, good errors, and tests (see parsing and compilers). It sits between a simple config format and a full language, and is often implemented over an internal AST.