Library / SDK
TarteelAI/quranic-universal-library avatar
TarteelAI/quranic-universal-library

Quranic Universal Library: a Rails CMS for managing Quranic text, audio and layout data

A comprehensive collection of Quran resources

1,080 stars138 forksRubyMIT

At a glance

What is it?
Quranic Universal Library is a Ruby on Rails content management system, built with Active Admin, for holding translations, tafsirs, audio, Arabic scripts, Mushaf layouts and grammatical data in one place, with versioning, import and export built in. It is an editor-facing system for organisations that maintain their own Quranic corpus, not an application for reading the Quran.
Who is it for?
Quranic Universal Library fits a team that already has people producing and proofreading Quranic content and needs somewhere to hold it with a revision trail, which means an organisation with a text workflow rather than a hobby project.
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 received new commits within the last day.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A content system for corpora, not an application for reading

Quranic Universal Library, or QUL, is described as a comprehensive content management system designed to manage Quranic data, including translations, tafsirs, audio, audio segments, Arabic scripts, Mushaf layouts, and much more. It is implemented using Ruby on Rails, and Active Admin is used for the admin interface. The project is by Tarteel, and the hosted site is at qul.tarteel.ai.

The scope is the important part. This is a system for the people who produce the content, not for the people who read it. The feature list is a list of content types and operations on them: translations and tafsirs that can be added, proofread, fixed and exported in different formats; audio that can be added both ayah by ayah and gapless, with audio segments managed and segment data exported; Arabic scripts that can be previewed ayah by ayah and word by word; Mushaf layouts that can be managed, previewed and exported; users with roles and permissions; Mutashabihat ul Quran data; Surah info in multiple languages; Quranic grammar and morphology data.

Those are the nouns of a publishing operation. Each one is a body of material that arrives from somewhere, needs checking by a person, and then has to leave the system in a format other software can read. The features that make it a content system rather than a database are the two ends of that pipeline, import data from different sources and export data in different formats, and the middle part, content versioning to keep track of all changes made to the content.

A related detail: the repository has no GitHub releases. Deployment, then, does not follow a published version cadence, and anyone tracking upgrades has to watch the repository rather than a release list.

Active Admin is the whole user interface story

The choice of Active Admin tells you a great deal about who this system is for.

Active Admin is a Rails engine that generates an administration interface from existing models, which means an editor gets forms, filters and tables without a separate front-end application to build and maintain. For a team whose job is proofreading Arabic text and attaching audio to ayahs, that is exactly the right shape of tool: the interface is a grid of records and a set of forms, and the cost of adding a new content type is a model rather than a front-end project.

It also has a consequence. The set of workflows an editor can perform is bounded by what the models expose, and the README does not describe a public API for the content, a headless mode, or a client-side application. The package.json in the repository lists a Vue 3 toolchain, esbuild, chart.js, chartkick, select2, trix, sortablejs, howler, hotkeys-js and syncfusion ej2-layouts among the dependencies, so there is a JavaScript front end inside this Rails application, and the repository has an esbuild.config.js and a config.ru. But the content management surface described in the feature list is the Active Admin one.

For a reader deciding whether to adopt, the practical question is whether Active Admin is sufficient for the editorial workflow you have in mind, in particular whether proofread and fix cycles need a diff view, side-by-side comparison, or a review queue, none of which appear in the feature list.

The compose file pins Postgres 14 and Redis 7

The repository ships a Dockerfile and a docker-compose.yml, and the compose file is the clearest statement of the runtime shape.

The database service runs postgres:14 with the durability settings turned off, which is a development-oriented choice:

yaml
  db:
    image: postgres:14
    command: >
      postgres -c fsync=off -c full_page_writes=off -c synchronous_commit=off
    environment:
      POSTGRES_DB: quran_community_tarteel
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    ports:
      - '5432:5432'
    volumes:
      - qul-postgres-data:/var/lib/postgresql/data
      - ./docker/dev/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U postgres']
      interval: 5s
      timeout: 5s
      retries: 5

The second service is Redis 7 on the standard port with a named volume, and the compose file defines two named volumes, qul-postgres-data and qul-redis-data. The init-db.sh script is mounted into the postgres container's entrypoint directory, so the database is seeded on first start, and the healthcheck uses pg_isready with a five second interval and five retries, which is what lets a dependent service wait for the database.

The Dockerfile shows a different, production-shaped stack: it starts from phusion/passenger-customizable:3.1.6 and installs Ruby 3.3 via the phusion build script, with an explicit rvm default of ruby-3.3.10. It also installs Node 24 LTS before the Ruby setup, and the comment explains why in unusually plain terms, since the phusion ruby script checks for the nodesource list and skips its own Node installation if present, and without it phusion installs its default Node 22 whose npm is broken because promise-retry is missing. That is a small but revealing detail: the image is assembled around a specific sequence of installers, and the order matters.

The build arguments and environment variables in that Dockerfile are extensive, and they divide into distinct groups: the Rails secrets and error reporting, a separate database for the Quran API alongside the CMS database, S3-style storage for the database backup bucket and for the QUL exported file storage, SMTP and mailer settings, and Cloudflare credentials. A deployment touches all of these groups.

Storage configuration falls back to safe defaults when it is unset

The .env.sample file in the repository is short, and what it says is worth reading carefully because it describes a fallback behaviour rather than a required value.

bash
# Leave these blank for local development - config/storage.yml falls back to
# safe defaults (a "missing" bucket and a https://fix.me endpoint) when unset.
# Only fill these in if you have real S3-compatible storage credentials.
QUL_STORAGE_ACCESS_KEY=
QUL_STORAGE_ACCESS_KEY_SECRET=
QUL_STORAGE_BUCKET=
QUL_STORAGE_PUBLIC_EXPORT=true
QUL_STORAGE_ENDPOINT=
QUL_STORAGE_REGION=

So the export feature, which is central to the system, writes to S3-compatible object storage, and the configuration keys for it are these six. When they are blank, storage.yml falls back to a missing bucket and a https://fix.me endpoint. That is a deliberate placeholder, and it means a fresh checkout starts without failing on absent credentials, and also that a misconfigured production instance can look healthy while pointing at a placeholder endpoint.

The public export flag is set to true in the sample, and it exists as a separate variable alongside the credential ones. Since exports are how other systems consume this data, whether that flag is on is a decision about who can reach the output.

The Dockerfile treats the same setting as a build argument, with ARG and ENV entries for DB_BACK_BUCKET, AWS_ACCESS_KEY, AWS_ACCESS_KEY_SECRET, AWS_BUCKET, ALLOW_PUBLIC_EXPORT, and then a separate group for the QUL storage: QUL_STORAGE_ACCESS_KEY, QUL_STORAGE_ACCESS_KEY_SECRET, QUL_STORAGE_BUCKET, QUL_STORAGE_PUBLIC_EXPORT, QUL_STORAGE_ENDPOINT, QUL_STORAGE_REGION. Two different sets of storage variables in one image, one for backups and one for exports, is a detail that will matter when the deployment is configured.

A Rails system with a JavaScript toolchain bolted alongside it

The repository root is a mix of two stacks, and understanding which is which explains a lot of the file layout.

The Ruby side is a conventional Rails application: a Gemfile, a Gemfile.lock, a Rakefile, a config.ru, a config/ directory, an app/ directory with the models, views and controllers, a db/ directory for migrations and seeds, and a test/ directory. There is a .rubocop.yml and a .ruby-version, plus a .ruby-gemset, which places the project firmly in the Ruby ecosystem's tooling.

The JavaScript side is newer and less conventional. The package.json names the package qul, marks it private, and lists esbuild at 0.25.12 along with esbuild-rails and esbuild-plugin-vue3, a Vue 3 stack with vuex, and a large set of administrative and charting libraries. The devDependencies bring cypress 15.9.0 and puppeteer 24.30.0, eslint, prettier, a linthtml stack for HTML linting, and size-limit with two plugins, which is a bundle size budget tool, so the project watches the weight of what it ships to the browser. There is also a bun.lock next to a yarn.lock, and a .node-version file, and a scripts/ directory.

Two JavaScript lockfiles worth noting: a yarn.lock and a bun.lock sit together in one root, which is a sign of a transitional state rather than a settled one, and a team adopting this repository will have to work out which is authoritative.

The documentation is organised the same way, split by role rather than by version. There is a docs index at qul.tarteel.ai/docs, and then separate paths for resource users (Getting Started, Downloading and Using Data, Resource Guides Index, Datasets, Data Model, Tutorials, FAQ) and for contributors (Contribute Code, Contribute Data). That split is a good sign for an adoption decision, because the path for a person who wants to download the data is separate from the path for a person who wants to change the code.

Where QUL is the wrong tool

There are three situations where this repository is a poor fit, and the feature list is what makes them visible.

The first is a single resource. If the goal is to obtain one tafsir, one translation or one set of audio segments and load it into an existing application, the CMS is the wrong shape. The README does describe export data in different formats, but exports are produced by running the system and configuring its storage, not by pointing a script at a repository. A team wanting the data alone is served by the Datasets and Downloading and Using Data pages, not by deploying the CMS.

The second is a reader-facing application. Nothing in the feature list is about search, recitation, reading modes, or a public API for end users. QUL is upstream of those products, and treating it as a product is a category error.

The third is an organisation with no editorial workflow. Content versioning, roles and permissions, proofreading and Surah info in multiple languages all presuppose people who edit content over time. A team with one static dataset and no one assigned to maintaining it will spend effort on the admin interface and get none of the benefit, since the value of the versioning model appears only after the first correction has to be traced.

One more practical limit deserves naming. There are no GitHub releases, so there is no published version to pin. A team that wants a reproducible deployment has to track the repository's commits and its docker image tags directly, and the .env.sample shows that a correct deployment also needs real object storage credentials, a Rails master key and a secret key base rather than the placeholder defaults.

Editorial conclusion

Quranic Universal Library fits a team that already has people producing and proofreading Quranic content and needs somewhere to hold it with a revision trail, which means an organisation with a text workflow rather than a hobby project. It is the wrong tool for a reader who wants an app, and for an engineer who wants a library to import a single tafsir into an existing service, since what the repository provides is a whole system with its own database, its own admin interface and its own storage configuration. Before adopting, read the data model and datasets pages under the QUL docs, check the Active Admin interface against the roles your editors need, and confirm that your deployment target matches the Postgres 14 and Redis 7 versions the compose file pins.

Frequently asked questions

What is the Quranic Universal Library used for?

It is a content management system for Quranic data, implemented in Ruby on Rails with Active Admin, covering translations, tafsirs, audio and audio segments, Arabic scripts, Mushaf layouts, Surah info, and Quranic grammar and morphology. It also handles import from different sources, export in different formats, and content versioning.

How do I run Quranic Universal Library locally?

The repository ships a Dockerfile and a docker-compose.yml with a postgres:14 service, a redis:7 service, named volumes and an init-db.sh script mounted into the database container, plus a .env.sample for the storage variables. The README does not give a command sequence, so the compose and Dockerfile in the repository are the starting point.

What is Active Admin used for in the Quranic Universal Library?

Active Admin implements the admin interface of the Rails application, so the editing surface for translations, tafsirs, audio and the other content types is generated from the models rather than built as a separate front end.

Where does the Quranic Universal Library store exported data?

The .env.sample file lists QUL_STORAGE_ACCESS_KEY, QUL_STORAGE_ACCESS_KEY_SECRET, QUL_STORAGE_BUCKET, QUL_STORAGE_PUBLIC_EXPORT, QUL_STORAGE_ENDPOINT and QUL_STORAGE_REGION, and it notes that config/storage.yml falls back to a missing bucket and a https://fix.me endpoint when these are left blank. Real S3-compatible credentials are needed for exports to work.

How do I contribute to the Quranic Universal Library?

The README points to two separate paths in the documentation, Contribute Code and Contribute Data, under the docs index at qul.tarteel.ai/docs, and says the complete contribution flow and PR checklist are described there. There is also a SECURITY.md and a .rubocop.yml in the repository root.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. TarteelAI/quranic-universal-library on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tarteelai-quranic-universal-library.svg)](https://hysenlabs.com/projects/tarteelai-quranic-universal-library)

Was this useful?