Swift Codable with human-friendly Markdown storage

What's New



Fixes a crash when decoding optional numbers out of columns that have mixed nil and non-nil values

What's Changed

  • Optimize parsing when there are records failing to decode by @icanzilb in #46
  • Adds infra to track the encoded structures by @icanzilb in #47
  • Splits tests into more files by @icanzilb in #48
  • Handles nil values encoded as empty strings by @icanzilb in #49

Full Changelog: 0.6.8...0.6.9


Markdown Swift coding with an eye on human interaction.

This library is still in flux until we find together what's the best way to use markdown encoding, check the issues and/or leave some feedback.


MarkCodable encodes Codable values as Markdown text and decodes Markdown strings as Swift values. Markdown-representation allows humans to easily edit values by hand using their favorite text editor on any operating system or in a web interface.

JSON is flexible but either too compact or too verbose to edit meaningfully by hand:

[{"number":134,"street":"main st.","isSocial":false,"price":{"price":1234.3199999999999,"currency":"USD"}},{"number":24,"street":"Secondary st.","isSocial":true,"price":{"price":9234.3199999999997,"currency":"JPY"}}]

In comparison, Markdown isn't as expressive but it's far simpler to view and edit by a human:

|isSocial|number|price.currency|price.price|street       |
|false   |134   |USD           |1234.32    |main st.     |
|true    |24    |JPY           |9234.32    |Secondary st.|

Thus, for the smaller scope of encoding data in an edit-friendly format, Markdown is a great choice.

Use cases

You encode or decode Codable values as with any other decoder, bar some limitations on nested data types:

// Encode into a Markdown string
let markdown = try MarkEncoder().encode([house1, house2])

// Decode from a Markdown string
let houses = try MarkDecoder()
    .decode([House].self, from: markdown)


Markdown is a viable alternative to json or yml files, especially for multiple configuration entries like per-environment or per-domain configurations, for example:

| environment | host      | port | user | schema |
| qa          | | 8080 | test | http   |
| production  | 2.317.1.2 | 9999 | app  | https  |

Test and mock objects

In unit tests you often times need a number of test objects to create the test setup. Those are sometimes a bit clunky to always create in code so you can either include the Markdown in your tests or have it as an .md file in your test bundle:

| userID | name | age | permissions |
|1       |peter | 32  |read         |
|2       |admin | 100 |read,write   |


For simple relational data, using MarkCodable will allow you or your users to simply edit the data in any plain text editor. This is how a small podcast database might look like:
| userID | name |
|1       | John |
|2       | Gui  |
| podcastID | name            | hosts |
|1          |Swift by Sundell | 1     |
|2          |Stacktrace       | 1,2   |

Load the items by reading the files, decoding the values, and optionally store them as indexed dictionaries:

let users = try MarkDecoder()
    .decode([User].self, from: String(contentsOfFile: ""))
    .reduce(into: [Int: User](), { $0[$] = $1 })

print(users[2]) // [userID: 2, name: Gui]


Use the package directly in Xcode or via SwiftPM.

dependencies: [
  .package(url: "", from: "0.6.0"),

Demo App

This package contains a target called marktest that showcases some demo code. Run that demo from the package folder via:

swift run marktest

To see a demo of a full SwiftUI app (~70 lines of Swift) using a GitHub-hosted Markdown file as backend, check out this repo.


MIT License, Marin Todorov (2022)

@icanzilb on Twitter

Help, feedback or suggestions?

  • There is a list of current bugs if you'd like to pick one.

  • There is also a list of currently planned enhancements.

  • Open an issue if you need help, if you found a bug, or if you want to discuss a feature request.

  • Open a PR if you want to make a change to the code.


  • Swift Tools 5.6.0
View More Packages from this Author


Last updated: Sun May 26 2024 06:47:34 GMT-0900 (Hawaii-Aleutian Daylight Time)