MarkdownDB: putting a folder of markdown into a queryable SQL database
Turn markdown files into structured, queryable data with JS. Build markdown-powered docs, blogs, and sites quickly and reliably.
At a glance
- What is it?
- MarkdownDB parses a folder of markdown into structured records and indexes them in SQLite, MySQL or PostgreSQL, so a blog or a wiki can be queried with SQL instead of grep. The extraction covers frontmatter, tags, links, tasks and computed fields, and the CLI does the indexing in one command.
- Who is it for?
- MarkdownDB fits a static site or wiki whose author wants to query content with SQL, for example to build an index page or a related-posts list without hand-maintaining it. It does not fit a project that needs runtime content from a CMS, since the index is a build step over a folder of files, and it does not fit a codebase that already has a content pipeline you like.
- 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 155 days ago.
- What is it written in?
- Mainly TypeScript, 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 content pipeline where the database is a build artefact
MarkdownDB is a JavaScript library that turns markdown files into a structured, queryable database, either SQL-based or simple JSON, and it exists to help you build rich markdown-powered sites. The description in the README is worth reading closely because it names the two halves. It parses your markdown files to extract structured data such as frontmatter and tags and builds a queryable index either in JSON files or in a local database, and it provides a lightweight JavaScript API for querying that index and using the data files in your application. So the database is not something the app talks to at request time, it is something the build produces. The topics list the lineage, with contentlayer and contentlayer-nextjs and contentlayer-typescript among them, and the roadmap explicitly credits the Contentlayer documentation for the computed fields idea, which tells you this project picked up where that one stopped.
Indexing a folder is one command
The quick start assumes a folder of markdown content such as blog posts, each with a YAML frontmatter header carrying metadata like title, date and tags. Indexing it is a single npx invocation, and the npm package is called mddb.
# npx mddb <path-to-folder-with-your-md-files>
npx mddb ./blogThat creates a markdown.db file in the current directory, which the README says you can preview with any SQLite viewer. Multiple directories can be indexed into one database at once.
# Index multiple directories into a single database
npx mddb ./blog ./docs ./notesThere is a subtlety in that, because the roadmap lists indexing multiple folders as still unfinished, with the author's own example of keeping blog files in a separate folder. Passing a file path rather than a folder is the diagnostic case, and the CLI prints the parsed JSON to stdout instead of building a database.
npx mddb ./blog/post.mdNon-markdown extensions still parse, but the CLI warns you that it expected a .md, .markdown or .mdx file.
Watching, and running your own script against the index
Rebuilding on every save is a flag rather than a second tool, so the watch mode is the natural way to work on a site.
npx mddb ./blog --watchThat command continuously watches the specified folder and rebuilds the database whenever a change is detected. The other half of the CLI is the exec mode, which runs a JavaScript module that calls the MarkdownDB APIs directly, with any arguments after the script path passed through.
npx mddb --exec ./scripts/report.mjs --flag valueInternally the exec mode uses node with the import flag to set up module resolution so that mddb resolves inside the script. There is a race to handle, since the database file may still be settling, and the wait-db-ms option addresses it by waiting until the file has been idle for a given number of milliseconds, and waiting indefinitely if it keeps updating.
npx mddb --exec --wait-db-ms 500 ./scripts/report.mjsA module can also be piped in over standard input, which is handy for a one-off query from a shell.
cat ./scripts/report.mjs | npx mddb --exec -What gets extracted: frontmatter, tags, links and tasks
The feature list is the clearest statement of what the library understands. Frontmatter metadata is extracted and added in a metadata field. Tags are extracted both from the frontmatter and from the body, where a hashtag in the text is treated as a tag. Links between files are extracted, in both the markdown link style and the wikilink style, which is what makes it possible to compute backlinks or find dead links. Tasks are extracted from list items in the checkbox form. Computed fields add new metadata properties derived from existing ones, for example a slug computed from the title, a title taken from the first heading, or a type derived from the folder the file lives in, so a folder of posts can be typed as blog posts. One item on the list is still open and matters: casting types, so that a date is a date rather than a string, which the README frames as being able to find all blog posts before a given date.
Querying it, and the three database backends
The payoff is that the indexed content can be queried with SQL. Getting every file carrying a given tag is a join between the files table and the file_tags table.
SELECT files.*
FROM files
INNER JOIN file_tags ON files._id = file_tags.file
WHERE file_tags.tag = 'a'The backends are chosen through Knex.js, and the README is explicit that all three provide the same API and features, so you can switch between them without changing your code. SQLite is the default and needs no additional setup, described as suited to local development and small to medium sites. MySQL is for larger sites and when you need a separate database server, and it requires the mysql2 package. PostgreSQL is described as enterprise grade with advanced features and requires the pg package. The dependency list confirms the arrangement, with knex and sqlite3 as direct dependencies and the two server drivers as peer dependencies, so you install the driver only for the backend you actually use.
The Node API, which is a single connection object
The programmatic route is a MarkdownDB client that you initialise once and share across your application. For SQLite the shape is small.
// @/lib/mddb.mjs
import { MarkdownDB } from "mddb";
const dbPath = "markdown.db";
const client = new MarkdownDB({
client: "sqlite3",
connection: {
filename: dbPath,
},
});
const clientPromise = client.init();
export default clientPromise;The MySQL and PostgreSQL versions follow the same pattern with a different client name and a richer connection block, and the README notes that the driver package has to be installed for those. The init method returns a promise, and the example exports that promise as the default export, which is the shape that lets a single connection be established once and used across the app. The TypeScript definitions ship with the package, and the manifest points types at the built declaration file and the main entry at the built index.
A young project with a long dependency list
The repository is a TypeScript library with the usual modern tooling. The scripts cover format checking and formatting with prettier, linting with eslint, a build through tsc against a separate library configuration, a watch mode, and a release through changesets with a publish step, and the prepare and prepublishOnly hooks run the build. Tests run under jest with the experimental VM modules flag, and the pretest step builds and then runs the CLI against a mocks content directory, which is a neat way to make the command line interface part of the test suite. The runtime dependencies tell you what the parsing is built on: gray-matter for frontmatter, remark-parse and remark-gfm with unified and unist-util-select for the markdown pipeline, a wiki link remark plugin, micromatch for the include and exclude patterns, chokidar for the watch mode, react-markdown, zod for validation, and knex with sqlite3 for the database side. The package requires Node 20 or newer, is MIT licensed, authored by Rufus Pollock, and the last push was on 2026-05-21 with the latest release being 0.9.5 from March 2024.
Editorial conclusion
MarkdownDB fits a static site or wiki whose author wants to query content with SQL, for example to build an index page or a related-posts list without hand-maintaining it. It does not fit a project that needs runtime content from a CMS, since the index is a build step over a folder of files, and it does not fit a codebase that already has a content pipeline you like. Verify first that the metadata you want to filter on is extracted as a string rather than a typed value, since the roadmap lists type casting as unfinished, and check whether you need multiple source folders, which the README also lists as still open.
Frequently asked questions
What does MarkdownDB do with my markdown files?
It parses them to extract structured data, including frontmatter metadata, tags from both the frontmatter and the body, links between files in markdown and wikilink form, and tasks, and it builds a queryable index in JSON files or in a local database. It can also add computed fields derived from existing metadata, such as a slug from a title.
How do I index a folder of markdown with MarkdownDB?
Run npx mddb with the path, for example npx mddb ./blog, using the mddb npm package. That creates a markdown.db file in the current directory. Passing a file path instead prints the parsed JSON to stdout, and the --watch flag rebuilds the database whenever a file in the folder changes.
Which databases does MarkdownDB support?
SQLite as the default with no extra setup, MySQL for larger sites, which needs the mysql2 package, and PostgreSQL, which needs the pg package. All three go through Knex.js and provide the same API, so you can switch between them without changing your application code.
Can I query the indexed content with SQL?
Yes. The README gives an example joining the files table with the file_tags table to find every file carrying a given tag. You can also run a JavaScript module against the index with the exec mode, optionally waiting for the database file to settle first.
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/flowershow-markdowndb)Was this useful?