Soukai: A different way to query PODs

I’ve been working for a while on an ODM called Soukai.

The idea of using this library is that it has a common interface to define data models, and using different engines it can interact with different data sources. This is similar to existing Active Record implementations. One of such engine is soukai-solid, which allows to store models in Solid PODs.

I know what some think about Active Record, and the eternal discussion if it’s correct using it vs Data Mappers. But I won’t go into that, suffice to say that this is an opinionated library and you don’t have to use it if you don’t like it. I just want to share my work so that it can help others :).

On that note, I think LDflex is already a great tool to work with Solid using the Data Mapper paradigm. Although I can’t say for sure because I haven’t used it extensively, my apologies if it isn’t a fair comparison.


So, how does this work? Here’s the classical example of interacting with a foaf:Person document.

First you’d define the Person model:

import { FieldType } from 'soukai';
import { SolidModel } from 'soukai-solid';

class Person extends SolidModel {
    static rdfContexts = {
        'foaf': '',

    static rdfsClasses = ['foaf:Person'];

    static fields = {
        name: FieldType.String,
        friendUrls: {
            type: FieldType.Array,
            rdfProperty: 'foaf:knows',
            items: { type: FieldType.Key },

And after setting up the engine, you can use it as such:

const alice = await Person.find('');

alert(`Hello, ${}!`);

// You should see something such as {"name": "Alice", "friendUrls": [...]} in the console

// Add a new friend
await alice.update({
    friendUrls: [

This is of course a very simple example, if you are interested in learning more I suggest that you read the documentation of both soukai and soukai-solid.

Current Status

I’ve used the library on a task manager I’m developing for Solid, Solid Focus. You can look at the source code of that project to learn how this is used in a real-world application.

This is still one of the very first versions of the library, but I’ve tried to write a thorough documentation of the current features. I’m eager to hear your opinions and get some feedback.


Dear NoelDeMartin I tried your application. I logged in with my inrupt solid account. I created a demo task list. When I relogin, all my data has gone. So doesn’t the app store the data to my pod. Does it only gets my name from the pod?

Nice! Just wondering, and I don’t know if this is possible or difficult, but have you considered generating soukai models from shapes given in shex or shacl?

You should check your POD to see if the data was created or not. I know there is a problem on the current deployed versions of inrupt and solid community PODs, and I reported it a some time ago: Seems like it was fixed for a while but there’s been a regression and it’s happening again. For me it works on node-solid-server 5.0.0 (commit hash bf5541ca35a50bc59f566230f710e27cd915beb0).

Yes! I actually don’t know much about shapes other than the basics, but I’ve considered having an rdfShape property or something of the sort. Maybe if I become familiar with shapes I’ll do it :).

1 Like

Will data created with each soukai-solid model resulted in a single turtle file?

How do you handle cross file query?

I guess you probably weren’t asking me for an explanation of shapes, since it’s pretty well explained in the shape expressions primer, and all I’ve done is read the primer and that was months ago. But I think I get the main idea. You said you know the basics, so you probably already know this, but in case it’s helpful I’ll say it here and then maybe any experts out there can correct me if I’m wrong:
An ontology describes an open world, whereas a shape describes a closed one. So for example a car ontology doesn’t say a car couldn’t have emotions or children, but if a car shape doesn’t include anything about emotions or children, then a car can’t have them.

How does LDflex do that?

Yes, each model will be a single file on the server. Cross-file queries right now are only supported using relationships, so that’s probably something to improve for some use-cases.

What this library does at its core is treating models as LDP Resources, so saving a new model instance will for example add the ldp:Resource class automatically, and there are some properties like ldpContainer to work with LDP Containers. One relationship that containers and resources have is ldp:contains, so that’s how you can get multiple models at once.

The interaction with a Solid POD is actually within a single file, so you can look at that if you want to know exactly what’s happening on the network:


Yes I have already read the primer and this post as well: Shaping Linked Data apps. But I haven’t really used them, so I only know them from theory. If I wanted to add them to the library I wouldn’t be confortable without having used them in practice first.

But yes, the concept seems to fit quite well with how I’ve done this so far. What I wrote on this post were only some basic examples, but you can also define other things on the model like this:

class User extends SolidModel {
    static rdfContexts = {
        'foaf': '',

    static rdfsClasses = ['foaf:Person'];

    static fields = {
        name: {
            type: FieldType.String,
            rdfProperty: 'foaf:name',
            required: true,
        inbox: {
            type: FieldType.Key,
            rdfProperty: 'foaf:mbox',
            required: true,

Great that you built this library! We’ll be adding it to the list on .

One thing I particularly like about which uses this library is how fast its UI is.

I also like how it defines reusable models, that could help with client-side validation!

1 Like