Skip to main content

conventions

Use when writing new packages, adding CLI commands, creating build plugins, or following Meteor code patterns. Covers package.js structure, file naming, and common code patterns.

Source facts

Repository
meteor/meteor
Last source activity
September 4, 2026 at 13:43
Detected SKILL.md language
English
Stars
44,794
Forks
5,257

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
conventions
description
Use when writing new packages, adding CLI commands, creating build plugins, or following Meteor code patterns. Covers package.js structure, file naming, and common code patterns.
# Code Conventions Package structure, file naming, and code patterns for the Meteor codebase. ## Package Structure Every Meteor package follows this structure: ``` packages/my-package/ ├── package.js # Package manifest (name, version, dependencies, exports) ├── my-package.js # Main implementation (or split by concern) ├── my-package-server.js # Server-only code (optional) ├── my-package-client.js # Client-only code (optional) ├── my-package-tests.js # Tests (loaded via api.addFiles in test mode) └── README.md # Documentation (optional) ``` ## Package.js Anatomy ```javascript Package.describe({ name: 'my-package', version: '1.0.0', summary: 'Brief description', git: 'https://github.com/meteor/meteor.git', documentation: 'README.md' }); Package.onUse(function(api) { api.versionsFrom(['3.0']); // Minimum Meteor version api.use([ 'ecmascript', // ES2015+ support 'mongo', // MongoDB integration 'tracker' // Reactivity (client) ]); api.use('accounts-base', { weak: true }); // Optional dependency api.mainModule('my-package-server.js', 'server'); api.mainModule('my-package-client.js', 'client'); api.export('MyPackage'); // Global export }); Package.onTest(function(api) { api.use(['tinytest', 'my-package']); api.addFiles('my-package-tests.js'); }); Npm.depends({ 'lodash': '4.17.21' // npm dependencies }); ``` ## File Naming Conventions | Pattern | Purpose | |---------|---------| | `*-server.js` | Server-only code | | `*-client.js` | Client-only code | | `*-common.js` | Shared code | | `*-tests.js` | Test files | | `*.d.ts` | TypeScript declarations | ## Common Patterns ### Adding a New Core Package 1. Create directory in `/packages/my-package/` 2. Add `package.js` with proper dependencies 3. Implement functionality with proper exports 4. Add tests in `*-tests.js` 5. Update version numbers if needed ### Modifying Build System Key files to understand: - `/tools/isobuild/bundler.js` - High-level bundling - `/tools/isobuild/compiler.js` - Package compilation - `/tools/project-context.js` - Dependency resolution - `/tools/cli/commands.js` - CLI command handlers ### Adding CLI Commands Edit `/tools/cli/commands.js` or create new command file: ```javascript main.registerCommand({ name: 'my-command', options: { 'option-name': { type: String, short: 'o' } }, catalogRefresh: new catalog.Refresh.Never() }, function(options) { // Implementation }); ``` ### WebApp Middleware Pattern ```javascript import { WebApp } from 'meteor/webapp'; // Add middleware before Meteor's default handlers WebApp.rawConnectHandlers.use('/api', (req, res, next) => { // Runs before authentication next(); }); // Add middleware after authentication WebApp.connectHandlers.use('/api', (req, res, next) => { // req.userId available if authenticated next(); }); ``` ### Build Plugin Pattern ```javascript // In package.js Package.registerBuildPlugin({ name: 'compile-my-files', use: ['ecmascript', 'caching-compiler'], sources: ['plugin.js'], npmDependencies: { 'my-compiler': '1.0.0' } }); // In plugin.js Plugin.registerCompiler({ extensions: ['myext'], archMatching: 'web' }, () => new MyCompiler()); class MyCompiler extends CachingCompiler { getCacheKey(inputFile) { return inputFile.getSourceHash(); } compileOneFile(inputFile) { const source = inputFile.getContentsAsString(); const compiled = transform(source); inputFile.addJavaScript({ data: compiled, path: inputFile.getPathInPackage() + '.js' }); } } ``` ### Using tools-core in Packages ```javascript // In package.js api.use('tools-core'); // In implementation import { logProgress, ensurePackageDependencies, getMeteorAppDir, spawnProcess } from 'meteor/tools-core'; // Declare host-app dependencies. The shared engine handles auto-install versus // manual instructions; do not gate it on meteor.autoInstallDeps yourself. await ensurePackageDependencies({ packageId: 'my-compiler', packageLabel: 'My Compiler', dependencies: [ { name: '@rspack/core', version: '1.7.1', semverCondition: 'gte', dev: true } ] }); // Spawn external process const proc = spawnProcess('npx', ['rspack', 'build'], { cwd: getMeteorAppDir(), onStdout: (data) => logProgress(data) }); ``` ## Version Patterns Meteor uses `X.Y.Z-rcN.M` versioning where: - `X.Y.Z` - Semantic version - `rcN` - Release candidate number - `M` - Package-specific revision
View on GitHub