npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@deorta-dev/remotly

v2.0.0

Published

Remote Deploy Toolkit — deploy Node apps via SSH

Downloads

378

Readme

@deorta-dev/remotly

Remote Deploy Toolkit — Automate deployment of Node.js / NestJS applications to remote servers via SSH.

npm install -g @deorta-dev/remotly
npx @deorta-dev/remotly deploy

Quick Start

# 1. Create configuration
remotly init
ini
# 2. Edit .remotly-config/global.yml with your server details

# 3. Deploy
remotly deploy                    # interactive
remotly deploy --app api          # headless
remotly deploy --parallel         # multiple apps in parallel

Documentation


CLI Commands

| Command | Description | |---------|-------------| | remotly deploy | Deploy applications to remote servers | | remotly list | List available applications | | remotly init | Create global deploy configuration | | remotly init-app <name> | Create per-app configuration | | remotly status | Check status of deployed services | | remotly logs <app> | Fetch logs from a deployed service | | remotly versions <app> | List available deployment versions | | remotly rollback <app> | Rollback to a previous version |

deploy Options

| Flag | Description | Default | |------|-------------|---------| | -a, --app <name> | App to deploy (repeatable) | prompt | | -c, --config <dir> | Config directory | ./.remotly-config | | -p, --parallel | Deploy in parallel | false | | --no-build | Skip build step | false | | --dry-run | Preview without executing | false | | --env-file <path> | Load additional .env file | — |

logs Options

| Flag | Description | Default | |------|-------------|---------| | -n, --lines <number> | Number of log lines | 50 | | -c, --config <dir> | Config directory | ./.remotly-config |

rollback Options

| Flag | Description | Default | |------|-------------|---------| | -v, --version <version> | Specific version to rollback to | previous version | | -c, --config <dir> | Config directory | ./.remotly-config |

Exit Codes

| Code | Meaning | |------|---------| | 0 | All deploys successful | | 1 | At least one deploy failed | | 2 | Configuration error | | 3 | SSH connection error |


Configuration

# .remotly-config/global.yml
global:
  transport:
    type: ssh
    host: "your-server.com"
    port: 22
    username: "deploy"
    privateKeyPath: "~/.ssh/id_rsa"

  nodeVersion: "20"
  installPath: "/opt/services/{appName}"

  # Service manager: "systemd" (default) or "pm2"
  serviceManager: "systemd"

  # Optional: pre-deploy commands
  preDeploy:
    - command: "mkdir -p /var/log/{appName}"
      description: "Create log directory"

  # Optional: system dependencies
  systemDependencies:
    check: true
    apt:
      - libnss3

  # Optional: post-deploy commands
  postDeploy:
    - command: "systemctl reload nginx"
      description: "Reload reverse proxy"

  # Optional: versioning (timestamped releases + rollback)
  versioning:
    enabled: true
    keepReleases: 5

  # Optional: extra files/directories to upload
  extraFiles:
    - source: "scripts/init.sh"
    - source: "config/"
      destination: "/etc/myapp/config/"

  env:
    NODE_ENV: "production"

apps:
  api:
    env:
      PORT: "3000"

Resolution order: Defaults → globalapps[appName] → per-app file → REMOTLY_* env → CLI flags

See CONFIG_SCHEMA.md for the complete parameter reference.


Programmatic API

import { deploy, deployMultiple, dryRun, scanApps, use } from '@deorta-dev/remotly';
import { firstValueFrom } from 'rxjs';

// Deploy a single app
const result = await firstValueFrom(deploy({ appName: 'api' }));
console.log(result.success); // true | false

// Deploy multiple
const results = await firstValueFrom(
  deployMultiple([
    { appName: 'api' },
    { appName: 'worker' },
  ], { parallel: true }),
);

// Preview
const plan = await firstValueFrom(dryRun({ appName: 'api' }));
console.log(plan.steps);

All async operations return RxJS Observables. The only exception is CLI command handlers which use firstValueFrom to bridge Observable → Promise.


Pipeline

| # | Step | Phase | Description | |---|------|-------|-------------| | 1 | pre-deploy-commands | build | Execute pre-deploy commands (local/remote) | | 2 | build | build | Execute build system | | 3 | validate-output | build | Verify output directory | | 4 | connect | transfer | SSH connection | | 5 | ensure-node | transfer | Verify/install Node.js on remote | | 6 | system-dependencies | transfer | Check/install system packages | | 7 | prepare-dir | transfer | Create remote directories (or release dir with versioning) | | 8 | transfer | transfer | Upload built files | | 9 | upload-extra-files | transfer | Upload extra files/directories | | 10 | symlink-current | transfer | Update current symlink (versioning only) | | 11 | install | install | Remote npm install | | 12 | service-install | install | Install service (systemd or PM2) | | 13 | service-start | start | Start/restart service | | 14 | verify | verify | Verify service is active | | 15 | post-deploy-commands | verify | Execute post-deploy commands (local/remote) |

Each phase has onBefore and onAfter hooks that plugins can intercept.


Plugins

import { use } from '@deorta-dev/remotly';
import { nxPlugin } from '@deorta-dev/remotly-plugin-nx';
import { systemdPlugin } from '@deorta-dev/remotly-plugin-systemd';
import { sshPlugin } from '@deorta-dev/remotly-plugin-ssh';

use(nxPlugin());
use(systemdPlugin());
use(sshPlugin());

Official Plugins

| Package | Purpose | |---------|---------| | @deorta-dev/remotly-plugin-nx | NX scanner + builder | | @deorta-dev/remotly-plugin-systemd | systemd service manager | | @deorta-dev/remotly-plugin-ssh | SSH transport | | @deorta-dev/remotly-plugin-pm2 | PM2 service manager | | @deorta-dev/remotly-plugin-docker | Docker deployment |

Creating a Plugin

import type { RemotlyPlugin } from '@deorta-dev/remotly';
import { of } from 'rxjs';

export const myPlugin = (): RemotlyPlugin => ({
  name: 'my-plugin',
  version: '1.0.0',
  hooks: {
    onAfterBuild: (ctx) => {
      ctx.log('info', `Build completed for ${ctx.appName}`);
      return of(void 0);
    },
  },
  transports: [
    {
      name: 'my-transport',
      transport: { /* ... */ },
    },
  ],
});

PM2 Support

Remotly supports PM2 as an alternative to systemd for process management. Set serviceManager: "pm2" in your config:

global:
  serviceManager: "pm2"

PM2 is auto-installed on the remote server if not present. The pipeline generates an ecosystem.config.js file.

Versioning & Rollback

Enable timestamped releases to support rollback:

global:
  versioning:
    enabled: true
    keepReleases: 5

When versioning is enabled, each deploy creates a timestamped directory under releases/{YYYYMMDDHHmmss}/, and current becomes a symlink to the active release. Old releases beyond keepReleases are automatically cleaned up.

# List all versions
remotly versions api

# Rollback to previous version
remotly rollback api

# Rollback to specific version
remotly rollback api -v 20240711143000

Extra Files

Upload additional files or directories with the deploy:

global:
  extraFiles:
    - source: "scripts/init.sh"              # relative project path
    - source: "config/"
      destination: "/etc/myapp/config/"      # remote destination (optional)

If destination is omitted, the file is uploaded relative to the target installation directory.

Secrets

Placeholders ${VAR_NAME} are resolved by chaining providers:

env:
  DATABASE_URL: "${DB_PASSWORD}"

Order: process.env.env file → plugin providers (AWS Secrets Manager, Vault, etc.)


Architecture

CLI layer (commander + inquirer + chalk)
    ↓
Core layer (Deployer + PipelineRunner)
    ↓
Scanner → Builder → Transport → ServiceManager → Secrets

Principles:

  • Functional programming — no classes, factory functions
  • RxJS Observables — no Promises in library code
  • No shared state — each deploy is independent
  • Plugin-based — everything is extensible

Development

npm run build          # tsup (ESM + CJS + DTS)
npm run dev            # watch mode
npm run typecheck      # tsc --noEmit
npm run lint           # eslint
npm test               # vitest
npm run test:coverage  # with coverage report

License

MIT — @deorta-dev