HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
plumatic
schema
Clojure2013–2022
plumatic / schema

schema

Clojure(Script) library for declarative data description and validation

34Distinct people
40Mentions
1Explicit recommenders
2.5KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Clojure(Script) library for declarative data description and validation

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

I don't have nearly the breadth of experience in Clojure as the circleci guys, but I found that Prismatic's Schema [0] works well for me vs. core.typed. I can selectively…

numlocked used a recommendation phrase. One indexed comment matches. This is a phrase match, not a verdict.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 8–Nov 15 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/15/2026, 2:59:53 AM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year40 dated mentions

Observed mentions: 2013-09-05 16:49:14 UTC to 2022-10-05 02:30:45 UTC.

0369122013-01-01 00:00:00 UTC to 2014-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments20132014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 6 mentions; 0 submissions, 6 comments2015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 11 mentions; 0 submissions, 11 comments2016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 8 mentions; 0 submissions, 8 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments20172018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 4 mentions; 0 submissions, 4 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2022

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20132013-01-01 00:00:00 UTC2014-01-01 00:00:00 UTC202
20142014-01-01 00:00:00 UTC2015-01-01 00:00:00 UTC606
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC11011
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC808
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC202
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC202
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC202
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC404
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC101
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC202

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
A Clojure(Script) library for declarative data description and validation. API docs. -- One of the difficulties with bringing Clojure into a team is the overhead of understanding the kind of data (e.g., list of strings, nested map from long to string to double) that a function expects and returns. While a full-blown type system is one solution to this problem, we present a lighter weight solution: schemas. (For more details on why we built Schema, check out this post.) Schema is a rich language for describing data shapes, with a variety of features: Data validation, with descriptive error messages of failures (targeted at programmers) Annotation of function arguments and return values, with optional runtime validation Schema-driven data coercion, which can automatically, succinctly, and safely convert complex data types (see the Coercion section below) Other Schema is also built into our plumbing and fnhouse libraries, which illustrate how we build services and APIs easily and safely with Schema Schema also supports experimental clojure.test.check data generation from Schemas, as well as completion of partial datums, features we've found very useful when writing tests as part of the schema-generators library Meet Schema A Schema is a Clojure(Script) data structure describing a data shape, which can be used to document and validate functions and data. (ns schema-examples (:require [schema.core :as s :include-macros true ;; cljs only ])) (s/defschema Data "A schema for a nested data type" {:a {:b s/Str :c s/Int} :d [{:e s/Keyword :f [s/Num]}]}) (s/validate Data {:a {:b "abc" :c 123} :d [{:e :bc :f [12.2 13 100]} {:e :bc :f [-1]}]}) ;; Success! (s/validate Data {:a {:b 123 :c "ABC"}}) ;; Exception -- Value does not match schema: ;; {:a {:b (not (instance? java.lang.String 123)), ;; :c (not (integer? "ABC"))}, ;; :d missing-required-key} The simplest schemas describe leaf values like Keywords, Numbers, and instances of Classes (on the JVM) and prototypes (in ClojureScript): ;; s/Any, s/Bool, s/Num, s/Keyword, s/Symbol, s/Int, and s/Str are cross-platform schemas. (s/validate s/Num 42) ;; 42 (s/validate s/Num "42") ;; RuntimeException: Value does not match schema: (not (instance java.lang.Number "42")) (s/validate s/Keyword :whoa) ;; :whoa (s/validate s/Keyword 123) ;; RuntimeException: Value does not match schema: (not (keyword? 123)) ;; On the JVM, you can use classes for instance? checks (s/validate java.lang.String "schema") ;; On JS, you can use prototype functions (s/validate Element (js/document.getElementById "some-div-id")) From these simple building blocks, we can build up more complex schemas that look like the data they describe. Taking the examples above: ;; list of strings (s/validate [s/Str] ["a" "b" "c"]) ;; nested map from long to String to double (s/validate {long {String double}} {1 {"2" 3.0 "4" 5.0}}) Since schemas are just data, you can also def them and reuse and compose them as you would expect: (def StringList [s/Str]) (def StringScores {String double}) (def StringScoreMap {long StringScores}) However, we encourage you to use s/defschema for this purpose to improve error messages: (s/defschema StringList [s/Str]) (s/defschema StringScores {String double}) (s/defschema StringScoreMap {long StringScores}) What about when things go bad? Schema's s/check and s/validate provide meaningful errors that look like the bad parts of your data, and are (hopefully) easy to understand. (s/validate StringList ["a" :b "c"]) ;; RuntimeException: Value does not match schema: ;; [nil (not (instance? java.lang.String :b)) nil] (s/validate StringScoreMap {1 {"2" 3.0 "3" [5.0]} 4.0 {}}) ;; RuntimeException: Value does not match schema: ;; {1 {"3" (not (instance? java.lang.Double [5.0]))}, ;; (not (instance? java.lang.Long 4.0)) invalid-key} See the More examples section below for more examples and explanation, or the custom Schemas types page for details on how Schema works under the hood. Beyond type hints If you've done much Clojure, you've probably seen code with documentation like this: (defprotocol TimestampOffsetter (offset-timestamp [this offset] "adds integer offset to stamped object and returns the result")) (defrecord StampedNames [^Long date names] ;; a list of Strings TimestampOffsetter (offset [this offset] (+ date offset))) (defn ^StampedNames stamped-names "names is a list of Strings" [names] (StampedNames. (str (System/currentTimeMillis)) names)) (def ^StampedNames example-stamped-names (stamped-names (map (fn [first-name] ;; takes and returns a string (str first-name " Smith")) ["Bob" "Jane"]))) Clojure's type hints make great documentation, but they fall short for complex types, often leading to ad-hoc descriptions of data in comments and doc-strings. This is better than nothing, but these ad hoc descriptions are often imprecise, hard to read, and prone to bit-rot. Schema provides macros s/defprotocol, s/defrecord, s/defn, s/def, and s/fn that help bridge this gap. These macros are just like their clojure.core counterparts, except they support arbitrary schemas as type hints on fields, arguments, and return values. This is a graceful extension of Clojure's type hinting system, because every type hint is a valid Schema, and Schemas that represent valid type hints are automatically passed through to Clojure. (s/defprotocol TimestampOffsetter (offset-timestamp :- s/Int [this offset :- s/Int])) (s/defrecord StampedNames [date :- Long names :- [s/Str]] TimestampOffsetter (offset [this offset] (+ date offset))) (s/defn stamped-names :- StampedNames [names :- [s/Str]] (StampedNames. (str (System/currentTimeMillis)) names)) (s/def example-stamped-names :- StampedNames (stamped-names (map (s/fn :- s/Str [first-name :- s/Str] (str first-name
Read the full README on GitHub

What Hacker News says

6 sources
Did you use Prismatic's Schema [1] at the time? It seems like that was developed for your exact problem/use-case. By the way; I don't think Rich makes fun of TDD, but of how little of TDD is left when you're working with purely functional, side-effect free, code: passing functions data and verifying that you get back the right thing. In practice every Clojure coder will tell you debugging is still a pain but that it's not a problem as long as you check each small, pure, function for correctness ... which is pretty close to, if not the same as, TDD. [1] https://github.com/Prismatic/schema
In Clojure 1.6 released
I am surprised that EDN is not making more progress as a data interchange format, especially now that it has fantastic validators and coercion libraries, such as Prismatic's Schema: https://github.com/prismatic/schema This is, by far, the most intelligent data exchange system I have ever seen. It offers a richer language of types than what is offered by JSON, it is as readable as YAML, it is far more concise than XML. And yet it seems unable to break out of the world of Clojure. But it deserves to be taken seriously as a data interchange language.
In Q – A Data Language
Most of the complaints in this article boil down to "macros are too powerful." I think this is the key part of the argument: "A smart programmer is not necessarily an empathetic language designer; they are occupations that require different skillsets. Giving any programmer on your team the ability to arbitrarily extend the compiler can lead to a bevy of strange syntax and hard-to-debug idiosyncrasies." There are at least 2 counter-arguments to this: 1.) in the simplest case, just restrict the use of macros. A team can easily adapt the rule that only the most experienced engineer on the team is allowed to write or approve macros. (And in my experience, the need for macros is fairly rare. I think my ratio is something like 100 or 200 normal functions for every macro that I write.) 2.) macros allow all kinds of interesting type checking, and
Read the rest
data structure validation, and therefore they make it surprisingly easy to validate data and types as your data and/or vars get passed around your system. Consider all of these very interesting tools you can use in the world of Clojure: Prismatic Schema which allows validation that a data structure matches a schema of (possibly nested) types: https://github.com/prismatic/schema and this now offers coercion, which makes this fantastic for importing JSON from other sub-systems or outside vendors: http://blog.getprismatic.com/blog/2014/1/4/schema-020-back-w... (I assume you could easily validate before giving data to Liberator to export your data while conforming to your schema: http://clojure-liberator.github.io/liberator/ ) There is work being done on an optional type system: https://github.com/clojure/core.typed Much effort has been made to make contract programming easy in Clojure: https://github.com/clojure/core.contracts But also I find the built-in syntax for writing pre and post assertions is clean and easy to use: http://blog.fogus.me/2009/12/21/clojures-pre-and-post/ In short, there are an abundance of mechanisms available with Clojure which help facilitate the enforcement of any kind of schema or contract, and some of these tools are enabled (and their syntax is made clean) thanks to macros. In short: macros can be used for evil, but they can also be used for good. They are very powerful, so everyone should be judicious about their use, but there is no reason to argue that macros render a Lisp unfit for programming in the large. Having said all that, I'll remind everyone that the ultimate counter-argument is offered by Paul Graham, in his essay "Beating the averages": http://www.paulgraham.com/avg.html If that essay does not convince you of the value of macros/lisp, then nothing will.
In Lisp: More is less
> but until you get some optional typing The schema library form the prismatic guys should be what you want, its pretty powerful. https://github.com/prismatic/schema Aria Haghighi - Prismatic's Schema for Server and Client-Side Data Shape Declaration and Validation (http://www.youtube.com/watch?v=o_jtwIs2Ot8&list=PLZdCLR02grL...) For static type checking: https://github.com/clojure/core.typed > possibly another syntax baked in Not needed in my mind. I would rather have less devs then C syntax. Not trying to be elitist but clojure will never not be a lisp, and if somebody can move from a(b) to (a b) then let him do python.
In Scala – 1 Star Would Not Program Again
About this: "until you get some optional typing" There is work being done on an optional type system: https://github.com/clojure/core.typed There are also some interesting experiments in enforcing specific data structures: https://github.com/prismatic/schema Much effort has been made to make contract programming easy in Clojure: https://github.com/clojure/core.contracts And if you would feel the urge to respond with something like "why is such important functionality in a library", I'll point out enforcing pre and post conditions (on a function) has a nice syntax that is part of the language: http://blog.fogus.me/2009/12/21/clojures-pre-and-post/ I find that every time I read an article about Scala I am left wondering "Why don't these people just use Clojure?"
In Scala – 1 Star Would Not Program Again

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.