Skip to main content

JavaScript

Use Convex from plain JavaScript (no TypeScript required).

Installation

npm install @convex-world/convex-ts
TypeScript Package

The package name is @convex-world/convex-ts but it works perfectly in plain JavaScript projects. The TypeScript definitions are optional.

Quick Start

import { Convex, KeyPair } from '@convex-world/convex-ts';

// Connect and query
const convex = new Convex('https://peer.convex.live');
const result = await convex.query('(balance #13)');
console.log('Balance:', result.value);

CommonJS

const { Convex, KeyPair } = require('@convex-world/convex-ts');

async function main() {
const convex = new Convex('https://peer.convex.live');
const result = await convex.query('(balance #13)');
console.log('Balance:', result.value);
}

main().catch(console.error);

Using Your Account

import { Convex, KeyPair } from '@convex-world/convex-ts';

const convex = new Convex('https://peer.convex.live');

// Load your key pair
const keyPair = KeyPair.fromSeed(process.env.CONVEX_SEED);
convex.setAccount('#1678', keyPair);

// Check balance
const info = await convex.getAccountInfo();
console.log('Balance:', info.balance / 1_000_000_000, 'Convex Coins');

// Transfer coins
const result = await convex.transfer('#456', 1_000_000_000);
console.log('Transaction:', result.hash);

Common Patterns

Query Multiple Accounts

const addresses = ['#9', '#10', '#11'];

for (const addr of addresses) {
const result = await convex.query(`(balance ${addr})`);
console.log(`${addr}: ${result.value} copper`);
}

Execute Convex Lisp

// Deploy a function
const deploy = await convex.transact(`
(def greet
(fn [name]
(str "Hello, " name "!")))
`);

// Call it
const result = await convex.transact('(greet "World")');
console.log(result.result); // "Hello, World!"

Error Handling

try {
const result = await convex.transfer('#456', 1_000_000_000);

if (result.status === 'success') {
console.log('✅ Success!');
} else {
console.error('❌ Failed:', result.error);
}
} catch (error) {
console.error('Network error:', error.message);
}

Package.json Setup

ES Modules

Add to your package.json:

{
"type": "module"
}

Running Scripts

# Node.js 18+
node script.js

# Or with tsx (handles both JS and TS)
npx tsx script.js

Complete Example

import { Convex, KeyPair } from '@convex-world/convex-ts';

async function main() {
// Connect
const convex = new Convex('https://peer.convex.live');

// Query (no account needed)
console.log('=== Query ===');
const balance = await convex.query('(balance #9)');
console.log('Convex Foundation:', balance.value, 'copper');

// Use your account
console.log('\n=== Account ===');
const keyPair = KeyPair.fromSeed(process.env.CONVEX_SEED);
convex.setAccount(process.env.CONVEX_ADDRESS, keyPair);

const info = await convex.getAccountInfo();
console.log('My balance:', info.balance / 1_000_000_000, 'coins');

// Transaction
console.log('\n=== Transaction ===');
const result = await convex.transact('(def my-data "Hello from JavaScript!")');
console.log('Transaction:', result.hash);
}

main().catch(console.error);

Run it:

CONVEX_SEED=your-seed CONVEX_ADDRESS=#1678 node app.js

Key Differences from TypeScript

No Type Annotations

// JavaScript - no types
const convex = new Convex('https://peer.convex.live');
const result = await convex.query('(balance #13)');

// TypeScript - with types
const convex: Convex = new Convex('https://peer.convex.live');
const result: Result = await convex.query('(balance #13)');

Runtime Validation

Without TypeScript, validate at runtime:

function validateConfig(config) {
if (!config.seed) {
throw new Error('Missing seed');
}
if (!config.address) {
throw new Error('Missing address');
}
return config;
}

const config = validateConfig({
seed: process.env.CONVEX_SEED,
address: process.env.CONVEX_ADDRESS
});

JSDoc for IntelliSense

Get autocomplete without TypeScript:

/**
* @param {string} address - Convex address
* @param {number} amount - Amount in copper
* @returns {Promise<any>}
*/
async function transfer(address, amount) {
return await convex.transfer(address, amount);
}

Browser Usage

With Module Bundler

import { Convex } from '@convex-world/convex-ts';

const convex = new Convex('https://peer.convex.live');

document.getElementById('queryBtn').addEventListener('click', async () => {
const result = await convex.query('(balance #9)');
document.getElementById('result').textContent = result.value;
});

For quick prototypes only:

<script type="module">
import { Convex } from 'https://cdn.jsdelivr.net/npm/@convex-world/convex-ts/+esm';

const convex = new Convex('https://peer.convex.live');
const result = await convex.query('(balance #9)');
console.log(result.value);
</script>

React (JavaScript)

import { useState, useEffect } from 'react';
import { Convex } from '@convex-world/convex-ts';

function ConvexBalance() {
const [balance, setBalance] = useState(null);

useEffect(() => {
const convex = new Convex('https://peer.convex.live');

convex.query('(balance #9)').then(result => {
setBalance(result.value);
});
}, []);

return (
<div>
Balance: {balance ? `${balance} copper` : 'Loading...'}
</div>
);
}

Further Reading

For detailed documentation, see the TypeScript guide. All concepts apply to JavaScript - just ignore the type annotations.

Key topics: