Skip to content
On this page


Flatpak is a sandboxed package format making packaging a bit trickier.

You can write flatpak configs in either json or yaml, but for the sake of being compatible with GNOME Builder, we'll create a data/APP_ID.json file.

During the build process shards won't be able to download the required libraries. For that reason I've written the following script that goes through your shard.lock and lib/ folder, collects shard versions and postinstall scripts and returns them in the correct format and with instructions:

# Generates the required sources for the flatpak based on the shard.lock

require "yaml"
require "json"
require "option_parser"

PATH = Path["lib"]

toJson = false

OptionParser.parse do |parser|
  parser.on "-j", "--json", "Whether it should export json instead of yaml" do
    toJson = true

lockfile = YAML.parse("shard.lock"))
shards = lockfile["shards"]

sources = [] of Hash(String, String)
postinstall_scripts = [] of String

shards.as_h.each do |x, y|
  version_type = "tag"
  version = "v" + y["version"].to_s
  if version.includes?("+git.commit.")
    version_type = "commit"
    version = version.split("+git.commit.")[-1]
  sources << {
    "type"       => "git",
    "url"        => y["git"].to_s,
    version_type => version,
    "dest"       => PATH.join(x.to_s).to_s,
end"lib/").each_child do |child|
  child_path = Path["lib/"].join(child)
  next unless
  shard_file = YAML.parse("shard.yml")))
  postinstall = shard_file["scripts"]?.try &.["postinstall"]?
  next unless postinstall
  postinstall_scripts << "cd #{child_path} && #{postinstall} && cd ../.."

commands = [] of String

# The following loop will go through all libs and symlink their libs to the parent folder.
commands << "for i in ./#{PATH}/*/; do ln -snf \"..\" \"$i/lib\"; done"
commands += postinstall_scripts if postinstall_scripts.size > 0

puts "Place the following snippet inside the 'build-commands' of your config:"
puts toJson ? commands.to_pretty_json : commands.to_yaml
puts "Keep in mind that postinstall scripts might need to be modified and audited."
puts ""
puts "Place the following snippet inside the 'sources' of your config:"
puts toJson ? sources.to_pretty_json : sources.to_yaml

Save it as and run:

$ crystal run

You can also pass the -j format if you want it in json (crystal run -- -j).

Follow the instructions and audit the postinstall scripts.

Now on the script writing, it depends on your package. You will have to install and build all dependencies as well as manage Crystal and shard versions. I don't want to focus too much on it so you are more than welcome to take a look at Collision's config.


Replace APP_ID with your app's ID.

Released under a Creative Commons Zero v1.0 Universal License