Quick Start
There are several ways to start, depending on how you like to work:
The steps below go from reading nanopublications to publishing your own. Steps 1 and 2 only need curl. Steps 3 and 4 use the command-line tool, which needs Java 21 or newer.
1. Fetch a nanopublication
Every nanopublication has a resolvable URI. Ask for TriG and you get the RDF:
curl -L -H "Accept: application/trig" \
https://w3id.org/np/RAlohixCBWPuGLSKA7mmR8k01EQvC_dRWwAU70kvvwKPo
Open the same URI in a browser and you get a human-readable view in Nanodash. The examples page has more to try.
2. Query the network
Published nanopublications are loaded into Nanopub Query instances. You can call ready-made queries through a REST API, or write your own SPARQL.
Ready-made queries
Each API endpoint runs a query that is itself published as a nanopublication. The endpoint URL is that nanopublication's ID plus the query name, and the placeholders in the query become URL parameters. This one is a full-text search:
API=https://query.knowledgepixels.com/api
curl -G $API/RAxdh5xkc6K6SMLY23yKu__zTWJPXeRFc0qgNNxkbOkpY/fulltext-search.csv \
--data-urlencode "query=Carabus granulatus"
Nanopublications cannot be changed, so a new version is a new nanopublication that supersedes the old one. The announcement of Nano Session #29, for example, was edited several times. This query finds the latest version, starting from the first:
API=https://query.knowledgepixels.com/api
curl -G $API/RAiRsB2YywxjsBMkVRTREJBooXhf2ZOHoUs5lxciEl37I/get-latest-version-of-np.csv \
--data-urlencode "np=https://w3id.org/np/RAgITiAZA5yLltVB07D47Oo-kKVHOemwAkXnCq_ZYJtME"
latest,date
https://w3id.org/np/RAiODd0jLYxpvX3EHNpJfJr3mtcHgAo-QmYWoNYRqHvE0,2026-03-17T19:04:07.326Z
The .csv suffix selects the result format, and .json works too.
To see exactly what an endpoint does, fetch its definition like any other nanopublication:
curl -L -H "Accept: application/trig" \
https://w3id.org/np/RAiRsB2YywxjsBMkVRTREJBooXhf2ZOHoUs5lxciEl37I
Its assertion contains the SPARQL query, where the placeholder ?_np_iri becomes the np parameter.
Because the definition is immutable too, an endpoint URL always runs the same query.
This query lists all available ones.
Your own SPARQL
The SPARQL endpoints cover all nanopublications. These are the five most recent ones:
curl -G https://query.knowledgepixels.com/repo/full \
-H "Accept: text/csv" \
--data-urlencode 'query=
PREFIX npa: <http://purl.org/nanopub/admin/>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?np ?label ?date WHERE {
GRAPH npa:graph { ?np dct:created ?date ; rdfs:label ?label . }
}
ORDER BY DESC(?date) LIMIT 5'
The npa:graph graph holds metadata that the query service adds for each nanopublication, such as its label, its date, and the public key it was validly signed with.
This query finds all nanopublications whose assertion mentions the beetle species, leaving out the ones that their authors retracted or superseded with a new version:
curl -G https://query.knowledgepixels.com/repo/full \
-H "Accept: text/csv" \
--data-urlencode 'query=
PREFIX np: <http://www.nanopub.org/nschema#>
PREFIX npa: <http://purl.org/nanopub/admin/>
PREFIX npx: <http://purl.org/nanopub/x/>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?np ?label ?date WHERE {
GRAPH ?assertion { ?s ?p <https://www.gbif.org/species/1036789> }
GRAPH npa:graph {
?np np:hasAssertion ?assertion ;
rdfs:label ?label ;
dct:created ?date ;
npa:hasValidSignatureForPublicKey ?pubkey .
FILTER NOT EXISTS {
?newer npx:invalidates ?np ; npa:hasValidSignatureForPublicKey ?pubkey .
}
}
}'
To experiment, use the SPARQL editor in your browser.
3. Verify a nanopublication
Download the command-line tool of nanopub-java from Maven Central:
V=$(curl -s https://repo1.maven.org/maven2/org/nanopub/nanopub/maven-metadata.xml \
| sed -n 's:.*<release>\(.*\)</release>.*:\1:p')
curl -L -o nanopub.jar \
https://repo1.maven.org/maven2/org/nanopub/nanopub/$V/nanopub-$V-jar-with-dependencies.jar
alias np='java -jar nanopub.jar'
Save the beetle nanopublication and check it:
curl -sL -H "Accept: application/trig" -o beetle.trig \
https://w3id.org/np/RAlohixCBWPuGLSKA7mmR8k01EQvC_dRWwAU70kvvwKPo
np check beetle.trig
Summary: 1 trusty with signature; 1 nanopub with issues
"Trusty with signature" means that the hash in the URI matches the content, and that the signature is valid.
The issue is only a warning that the nanopublication was created more than an hour ago, which matters when you publish a new one (np check -v shows the details).
Now change a single label and check again:
sed 's/Linnaeus, 1758"/Linnaeus"/' beetle.trig > tampered.trig
np check tampered.trig
Looks like a trusty nanopub BUT VERIFICATION FAILED: https://w3id.org/np/RAlohixCBWPuGLSKA7mmR8k01EQvC_dRWwAU70kvvwKPo
Summary: 1 valid (not trusty); 1 nanopub with issues
4. Publish your own
Create a key pair. It is written to ~/.nanopub/, and existing keys are never overwritten:
np mkkeys
Write a nanopublication. It uses a temporary URI, which signing replaces with the final, hash-based one:
cat > hello.trig <<EOF
@prefix this: <http://purl.org/nanopub/temp/np001/> .
@prefix sub: <http://purl.org/nanopub/temp/np001/> .
@prefix np: <http://www.nanopub.org/nschema#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix orcid: <https://orcid.org/> .
@prefix wd: <http://www.wikidata.org/entity/> .
@prefix wdt: <http://www.wikidata.org/prop/direct/> .
sub:Head {
this: a np:Nanopublication ;
np:hasAssertion sub:assertion ;
np:hasProvenance sub:provenance ;
np:hasPublicationInfo sub:pubinfo .
}
sub:assertion {
wd:Q148 wdt:P36 wd:Q956 . # China - capital - Beijing
}
sub:provenance {
sub:assertion prov:wasAttributedTo orcid:0000-0002-1825-0097 .
}
sub:pubinfo {
this: dct:created "$(date -u +%Y-%m-%dT%H:%M:%SZ)"^^xsd:dateTime ;
dct:creator orcid:0000-0002-1825-0097 ;
dct:license <https://creativecommons.org/licenses/by/4.0/> ;
rdfs:label "The capital of China is Beijing" .
}
EOF
Replace 0000-0002-1825-0097 with your own ORCID iD. This one belongs to Josiah Carberry, ORCID's fictional test researcher.
Then sign the nanopublication and publish it to the test server:
np sign -s https://orcid.org/0000-0002-1825-0097 -o hello.signed.trig hello.trig
np publish -u https://test.registry.knowledgepixels.com/ hello.signed.trig
grep '@prefix this:' hello.signed.trig
The last line shows the trusty URI of your new nanopublication.
publish may warn that no templates are declared. Templates only matter for how Nanodash displays and edits a nanopublication, so you can ignore this warning here.
Two things to know before you publish on the live network, which is what publish does without -u:
- Nothing can be deleted. You can supersede a nanopublication with a new version, or retract it with
np retract, but the original stays on the network. - Your key has to be linked to you. A signature proves which key signed, not who owns the key. For your nanopublications to be attributed to your ORCID iD, you declare your key in an introduction nanopublication (example), which an already trusted user then endorses. Nanodash generates a key for you automatically, and shows you how to publish the introduction.
From code
The same steps in JavaScript with nanopub-js (npm install @nanopub/nanopub-js):
import { Nanopub, NanopubClient } from '@nanopub/nanopub-js';
import { readFileSync } from 'node:fs';
import { homedir } from 'node:os';
// Fetch and search
const client = new NanopubClient();
console.log(await client.fetchNanopub(
'https://w3id.org/np/RAlohixCBWPuGLSKA7mmR8k01EQvC_dRWwAU70kvvwKPo'));
for await (const row of client.findNanopubsWithText('Carabus granulatus')) {
console.log(row.np, row.label);
}
// Run a ready-made query
for await (const row of client.runQueryTemplate(
'RAiRsB2YywxjsBMkVRTREJBooXhf2ZOHoUs5lxciEl37I/get-latest-version-of-np',
{ np: 'https://w3id.org/np/RAgITiAZA5yLltVB07D47Oo-kKVHOemwAkXnCq_ZYJtME' },
)) {
console.log(row.latest, row.date);
}
// Sign and publish to the test server
const np = Nanopub.fromRdf(readFileSync('hello.trig', 'utf8'), 'trig', {
privateKey: readFileSync(`${homedir()}/.nanopub/id_rsa`, 'utf8'),
orcid: 'https://orcid.org/0000-0002-1825-0097',
});
await np.sign();
const { uri } = await np.publish('https://test.registry.knowledgepixels.com/np/');
console.log(uri);
There are also libraries for Python, Java, and Rust, listed under Tools.
Next steps
- Read the guidelines for the formal structure of nanopublications.
- See how the network fits together in the technical architecture.
- Create nanopublications from templates in your browser with Nanodash.
- Let an AI coding agent do all of the above with the nanopub Agent Skill.
- Ask questions in the Matrix channel.