<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: ronak navadia</title>
    <description>The latest articles on Forem by ronak navadia (@ronak_navadia).</description>
    <link>https://forem.com/ronak_navadia</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3068048%2Fc14ede0e-8bc9-4593-a8f7-d064619ea84f.png</url>
      <title>Forem: ronak navadia</title>
      <link>https://forem.com/ronak_navadia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ronak_navadia"/>
    <language>en</language>
    <item>
      <title>Level Up Your NestJS App with BullMQ Queues, DLQs &amp; Bull Board</title>
      <dc:creator>ronak navadia</dc:creator>
      <pubDate>Thu, 28 Aug 2025 17:03:18 +0000</pubDate>
      <link>https://forem.com/ronak_navadia/level-up-your-nestjs-app-with-bullmq-queues-dlqs-bull-board-5hnn</link>
      <guid>https://forem.com/ronak_navadia/level-up-your-nestjs-app-with-bullmq-queues-dlqs-bull-board-5hnn</guid>
      <description>&lt;p&gt;In this guide, we’ll walk through how to integrate BullMQ with NestJS using the WorkerHost processor pattern, as recommended in the official NestJS documentation. Along the way, we’ll enhance our job processing system with Bull Board for real-time monitoring and set up a Dead Letter Queue (DLQ) to catch and manage poison jobs. To tie everything together, we'll build a simple authentication system with a signup endpoint that enqueues a welcome email job—demonstrating how background processing can streamline user workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  📂 Folder Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
│── app.module.ts
│── main.ts
│
├── config/
│   └── bull.config.ts
│
├── modules/
│   ├── auth/
│   │   ├── auth.controller.ts
│   │   ├── auth.service.ts
│   │   └── auth.module.ts
│   │
│   └── queue/
│       ├── queue.constants.ts
│       ├── queue.module.ts
│       ├── queue.service.ts         # producers
│       └── processors/
│           ├── appointment.processor.ts  # WorkerHost
│           └── dlq.processor.ts          # WorkerHost (DLQ)
│
└── .env

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📦 Install Dependencies
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install bullmq ioredis class-validator class-transformer
npm install @bull-board/api @bull-board/express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ⚙️ Environment Configs (.env)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PORT=3000

# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
REDIS_USE_TLS=false

# Queue defaults
QUEUE_DEFAULT_ATTEMPTS=4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧭 Queue Constants (src/modules/queue/queue.constants.ts)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export enum QueueNames {
  APPOINTMENT = 'appointment',
  APPOINTMENT_DLQ = 'appointment-dlq', // Dead Letter Queue
}

export const JobNames = {
  SCHEDULE_APPOINTMENT: 'schedule-appointment',
  APPOINTMENT_DIGEST: 'appointment-digest',
  DEAD_LETTER: 'dead-letter',
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔧 Bull Config (src/config/bull.config.ts)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/config/bull.config.ts
import { ConfigModule, ConfigService } from '@nestjs/config';

export const bullQueueConfig = {
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: async (configService: ConfigService) =&amp;gt; {
    const useTls =
      configService.get&amp;lt;string&amp;gt;('REDIS_USE_TLS') === 'true' ||
      (configService.get&amp;lt;boolean&amp;gt;('REDIS_USE_TLS') as any) === true;

    return {
      connection: {
        host: configService.get&amp;lt;string&amp;gt;('REDIS_HOST'),
        port: Number(configService.get&amp;lt;number&amp;gt;('REDIS_PORT')),
        password: configService.get&amp;lt;string&amp;gt;('REDIS_PASSWORD') || undefined,
        db: Number(configService.get&amp;lt;number&amp;gt;('REDIS_DB') || 0),
        ...(useTls &amp;amp;&amp;amp; { tls: {} }),
      },
      defaultJobOptions: {
        attempts: Number(configService.get&amp;lt;number&amp;gt;('QUEUE_DEFAULT_ATTEMPTS') || 4),
        backoff: { type: 'exponential', delay: 3000 },
        removeOnComplete: { age: 3600, count: 1000 },
        removeOnFail: { age: 24 * 3600, count: 1000 },
      },
    };
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🏗 App Module (src/app.module.ts)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { BullModule } from '@nestjs/bullmq';
import { bullQueueConfig } from './config/bull.config';
import { QueueModule } from './modules/queue/queue.module';
import { AuthModule } from './modules/auth/auth.module';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    BullModule.forRootAsync(bullQueueConfig), // &amp;lt;- as requested
    QueueModule,
    AuthModule,
  ],
})
export class AppModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📦 Queue Module (src/modules/queue/queue.module.ts)
&lt;/h2&gt;

&lt;p&gt;Registers both the main queue and the DLQ, and wires processors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { BullModule } from '@nestjs/bullmq';
import { QueueNames } from './queue.constants';
import { QueueService } from './queue.service';
import { AppointmentProcessor } from './processors/appointment.processor';
import { DlqProcessor } from './processors/dlq.processor';

@Module({
  imports: [
    BullModule.registerQueue({
      name: QueueNames.APPOINTMENT,
      // per-queue defaults (can override root defaults)
      defaultJobOptions: {
        attempts: 4,
        backoff: { type: 'exponential', delay: 3000 },
        removeOnComplete: { age: 1800, count: 500 },
        removeOnFail: { age: 24 * 3600, count: 1000 },
      },
    }),
    BullModule.registerQueue({
      name: QueueNames.APPOINTMENT_DLQ,
      defaultJobOptions: {
        removeOnComplete: true,
      },
    }),
  ],
  providers: [QueueService, AppointmentProcessor, DlqProcessor],
  exports: [QueueService],
})
export class QueueModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📨 Producer Service (src/modules/queue/queue.service.ts)
&lt;/h2&gt;

&lt;p&gt;Adds jobs, delayed jobs, and a repeatable digest. (We keep producer isolated here and call it from AuthService.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Injectable } from '@nestjs/common';
import { InjectQueue } from '@nestjs/bullmq';
import { Queue, JobsOptions } from 'bullmq';
import { JobNames, QueueNames } from './queue.constants';

@Injectable()
export class QueueService {
  constructor(
    @InjectQueue(QueueNames.APPOINTMENT) private readonly appointmentQueue: Queue,
  ) {}

  async addAppointmentJob(data: { userId: string; email: string; name: string }, opts?: JobsOptions) {
    // Idempotency via jobId (prevents duplicates)
    const jobId = opts?.jobId ?? `welcome:${data.email}`;
    return this.appointmentQueue.add(JobNames.SCHEDULE_APPOINTMENT, data, {
      jobId,
      attempts: 4, // ensure attempts is set on the job so DLQ logic can read it
      backoff: { type: 'exponential', delay: 3000 },
      ...opts,
    });
  }

  async addDelayedAppointment(data: { userId: string; email: string; name: string }, delayMs: number) {
    return this.addAppointmentJob(data, { delay: delayMs });
  }

  async addRepeatableDigest() {
    return this.appointmentQueue.add(JobNames.APPOINTMENT_DIGEST, {}, { repeat: { cron: '0 9 * * *' } });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ⚙️ Appointment Processor (WorkerHost) with DLQ routing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Implements work in process(job).&lt;/li&gt;
&lt;li&gt;Emits worker events (waiting, active, stalled, paused, resumed, drained).&lt;/li&gt;
&lt;li&gt;On final failure (attempts exhausted), it adds a job to DLQ with a small payload.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/modules/queue/processors/appointment.processor.ts
import { Injectable, Logger } from '@nestjs/common';
import { Processor, WorkerHost, OnWorkerEvent, InjectQueue } from '@nestjs/bullmq';
import { Job, Queue } from 'bullmq';
import { JobNames, QueueNames } from '../queue.constants';

@Processor(QueueNames.APPOINTMENT)
@Injectable()
export class AppointmentProcessor extends WorkerHost {
  private readonly logger = new Logger(AppointmentProcessor.name);

  constructor(
    @InjectQueue(QueueNames.APPOINTMENT_DLQ) private readonly dlq: Queue,
  ) {
    super();
  }

  // Main work
  async process(job: Job&amp;lt;{ userId: string; email: string; name: string }&amp;gt;): Promise&amp;lt;any&amp;gt; {
    this.logger.log(`Processing job ${job.id} for ${job.data.email}`);
    await job.updateProgress(10);

    // Simulate sending a welcome email (replace with real provider call)
    await simulateSendWelcomeEmail(job.data.email, job.data.name);

    await job.updateProgress(100);
    this.logger.log(`Completed job ${job.id}`);
    return { ok: true };
  }

  // Worker events (observability)
  @OnWorkerEvent('waiting')
  onWaiting(jobId: string) {
    this.logger.log(`Event: waiting jobId=${jobId}`);
  }

  @OnWorkerEvent('active')
  onActive(job: Job) {
    this.logger.log(`Event: active jobId=${job?.id}`);
  }

  @OnWorkerEvent('stalled')
  onStalled(job: Job) {
    this.logger.warn(`Event: stalled jobId=${job?.id}`);
  }

  @OnWorkerEvent('paused')
  onPaused() {
    this.logger.warn('Event: worker paused');
  }

  @OnWorkerEvent('resumed')
  onResumed() {
    this.logger.log('Event: worker resumed');
  }

  @OnWorkerEvent('drained')
  onDrained() {
    this.logger.log('Event: worker drained');
  }

  @OnWorkerEvent('failed')
  async onFailed(job: Job | undefined, err: Error) {
    const id = job?.id ?? 'unknown';
    const attemptsMade = job?.attemptsMade ?? 0;
    const maxAttempts = job?.opts?.attempts ?? 1; // we set attempts on each job in the producer

    this.logger.error(`Event: failed jobId=${id} attemptsMade=${attemptsMade}/${maxAttempts} err=${err?.message}`);

    // **DLQ routing**: only when attempts exhausted (poison job)
    if (job &amp;amp;&amp;amp; attemptsMade &amp;gt;= maxAttempts) {
      await this.routeToDLQ(job, err);
    }
  }

  private async routeToDLQ(job: Job, err: Error) {
    try {
      await this.dlq.add(JobNames.DEAD_LETTER, {
        originalJobId: job.id,
        name: job.name,
        queue: QueueNames.APPOINTMENT,
        data: job.data,                // keep small—prefer references/IDs in real apps
        reason: err?.message ?? 'unknown',
        attemptsMade: job.attemptsMade,
        maxAttempts: job.opts.attempts ?? null,
        failedAt: new Date().toISOString(),
      }, { removeOnComplete: true });

      this.logger.warn(`Job ${job.id} moved to DLQ (${QueueNames.APPOINTMENT_DLQ})`);
    } catch (dlqErr) {
      this.logger.error(`Failed to push job ${job.id} to DLQ: ${dlqErr?.message}`);
    }
  }
}

// Simulated email sender (10% transient failure to demo retries/backoff)
async function simulateSendWelcomeEmail(email: string, name: string) {
  await new Promise((r) =&amp;gt; setTimeout(r, 200));
  if (!email) throw new Error('Invalid email');
  if (Math.random() &amp;lt; 0.1) throw new Error('Transient mail provider error');
  return true;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧰 DLQ Processor (WorkerHost)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Handles jobs placed in DLQ (e.g., persist to DB, alert ops).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/modules/queue/processors/dlq.processor.ts
import { Injectable, Logger } from '@nestjs/common';
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Job } from 'bullmq';
import { JobNames, QueueNames } from '../queue.constants';

@Processor(QueueNames.APPOINTMENT_DLQ)
@Injectable()
export class DlqProcessor extends WorkerHost {
  private readonly logger = new Logger(DlqProcessor.name);

  async process(job: Job&amp;lt;{
    originalJobId: string;
    name: string;
    queue: string;
    data: any;
    reason: string;
    attemptsMade: number;
    maxAttempts: number | null;
    failedAt: string;
  }&amp;gt;) {
    this.logger.warn(
      `DLQ: jobId=${job.id} original=${job.data.originalJobId} reason="${job.data.reason}"`,
    );

    // TODO:
    // - Persist to DB for triage
    // - Create an incident/alert
    // - Optionally implement auto-retry logic back to main queue after inspection

    return { handled: true };
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  👤 Auth Module — Signup API (Producer outside queue module)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;src/modules/auth/auth.controller.ts&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Body, Controller, Post } from '@nestjs/common';
import { IsEmail, IsString, MinLength } from 'class-validator';
import { AuthService } from './auth.service';

class SignupDto {
  @IsEmail()
  email: string;

  @IsString()
  @MinLength(3)
  name: string;

  @IsString()
  @MinLength(6)
  password: string;
}

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post('signup')
  async signup(@Body() dto: SignupDto) {
    const res = await this.authService.signup(dto);
    return { ok: true, queuedJobId: res.jobId };
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;src/modules/auth/auth.service.ts&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Injectable } from '@nestjs/common';
import { QueueService } from '../queue/queue.service';

@Injectable()
export class AuthService {
  constructor(private readonly queueService: QueueService) {}

  async signup(dto: { email: string; name: string; password: string }) {
    // 1) Create user in DB (omitted)
    const userId = 'generated-user-id';

    // 2) Enqueue welcome/appointment job (idempotent by jobId)
    const job = await this.queueService.addAppointmentJob({
      userId,
      email: dto.email,
      name: dto.name,
    });

    return { jobId: job.id };
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;src/modules/auth/auth.module.ts&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { QueueModule } from '../queue/queue.module';

@Module({
  imports: [QueueModule],
  controllers: [AuthController],
  providers: [AuthService],
})
export class AuthModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🌐 Bull Board at /bull-board (src/main.ts)
&lt;/h2&gt;

&lt;p&gt;Mounts Bull Board using the queue instances from Nest DI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { createBullBoard } from '@bull-board/api';
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
import { ExpressAdapter } from '@bull-board/express';
import { getQueueToken } from '@nestjs/bullmq';
import { QueueNames } from './modules/queue/queue.constants';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));

  const serverAdapter = new ExpressAdapter();
  serverAdapter.setBasePath('/bull-board');

  // Get queues from Nest DI
  const appointmentQueue = app.get(getQueueToken(QueueNames.APPOINTMENT));
  const dlqQueue = app.get(getQueueToken(QueueNames.APPOINTMENT_DLQ));

  createBullBoard({
    queues: [new BullMQAdapter(appointmentQueue), new BullMQAdapter(dlqQueue)],
    serverAdapter,
  });

  app.use('/bull-board', serverAdapter.getRouter());

  const port = process.env.PORT || 3000;
  await app.listen(port);
  console.log(`App:        http://localhost:${port}`);
  console.log(`Bull Board: http://localhost:${port}/bull-board`);
}
bootstrap();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📘 Topics &amp;amp; Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔁 Retries &amp;amp; Backoff
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;attempts&lt;/code&gt; and &lt;code&gt;backoff&lt;/code&gt; on each job (or via &lt;code&gt;defaultJobOptions&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Throw in &lt;code&gt;process(job)&lt;/code&gt; to trigger retry.&lt;/li&gt;
&lt;li&gt;Exponential backoff is safer for flaky downstream providers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⏱ Delayed &amp;amp; Repeatable Jobs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Delay: &lt;code&gt;queue.add(name, data, { delay: ms })&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Repeat: &lt;code&gt;queue.add(name, data, { repeat: { cron: '0 9 * * *' }})&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Remove a repeatable with &lt;code&gt;queue.removeRepeatable(...)&lt;/code&gt; when no longer needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚠️ Error Handling (Throw vs Fail, DLQ, Poison Jobs)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Throw inside &lt;code&gt;process()&lt;/code&gt; → failed attempt recorded, retried until attempts exhausted.&lt;/li&gt;
&lt;li&gt;On final failure, route to DLQ (see &lt;code&gt;AppointmentProcessor.onFailed()&lt;/code&gt;), store minimal payload (IDs/refs) and reason.&lt;/li&gt;
&lt;li&gt;Poison jobs should end up in DLQ; review and requeue manually (or via an ops flow).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔐 Idempotency &amp;amp; Dedup
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;jobId&lt;/code&gt; like &lt;code&gt;welcome:${email}&lt;/code&gt; to dedupe enqueues.&lt;/li&gt;
&lt;li&gt;Make processing idempotent (e.g., DB flag “email_sent” checked before sending).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🚦 Rate Limiting &amp;amp; Throughput Tuning
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prefer horizontal scaling (multiple worker processes/instances).&lt;/li&gt;
&lt;li&gt;Keep &lt;code&gt;concurrency&lt;/code&gt; reasonable to avoid saturating downstream services.&lt;/li&gt;
&lt;li&gt;For provider rate limits, add throttling middleware or use Worker-level limiter (if you run custom workers).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📡 Worker/Queue Events
&lt;/h3&gt;

&lt;p&gt;Handled via &lt;code&gt;@OnWorkerEvent&lt;/code&gt;: &lt;code&gt;waiting&lt;/code&gt;, &lt;code&gt;active&lt;/code&gt;, &lt;code&gt;stalled&lt;/code&gt;, &lt;code&gt;paused&lt;/code&gt;, &lt;code&gt;resumed&lt;/code&gt;, &lt;code&gt;progress&lt;/code&gt;, &lt;code&gt;completed&lt;/code&gt;, &lt;code&gt;failed&lt;/code&gt;, &lt;code&gt;drained&lt;/code&gt;.&lt;br&gt;
Use these for metrics, logs, alerts, and DLQ routing.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧹 Cleanup Policies
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;removeOnComplete&lt;/code&gt; / &lt;code&gt;removeOnFail&lt;/code&gt; to avoid Redis bloat.&lt;/li&gt;
&lt;li&gt;Periodically clean old jobs (Bull Board or code).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛑 Graceful Shutdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Nest + @nestjs/bullmq gracefully tears down workers.&lt;/li&gt;
&lt;li&gt;Avoid SIGKILL; let in-flight jobs finish.&lt;/li&gt;
&lt;li&gt;If you hold raw Queue instances elsewhere, close them in &lt;code&gt;onModuleDestroy&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔭 Observability
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Bull Board for inspection.&lt;/li&gt;
&lt;li&gt;Log worker events.&lt;/li&gt;
&lt;li&gt;Export metrics (counts, durations, failure ratio) to Prometheus/Grafana.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔎 Accessing Bull Board
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Start the app: &lt;code&gt;npm run start:dev&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Visit: &lt;code&gt;http://localhost:3000/bull-board&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Inspect queues, retry/remove failed jobs, watch job progress.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>javascript</category>
      <category>node</category>
      <category>redis</category>
    </item>
    <item>
      <title>Bull: The Robust Job and Queue System.</title>
      <dc:creator>ronak navadia</dc:creator>
      <pubDate>Mon, 25 Aug 2025 17:16:10 +0000</pubDate>
      <link>https://forem.com/ronak_navadia/exploring-bull-a-powerful-job-queue-for-nodejs-18hl</link>
      <guid>https://forem.com/ronak_navadia/exploring-bull-a-powerful-job-queue-for-nodejs-18hl</guid>
      <description>&lt;p&gt;Now that we understand what queues are and why they’re important, let’s talk about &lt;strong&gt;Bull&lt;/strong&gt; — one of the most widely used job queue libraries in Node.js.  &lt;/p&gt;

&lt;p&gt;If your app needs to send emails, process payments, generate reports, or handle background tasks, Bull makes your life a lot easier.  &lt;/p&gt;




&lt;h2&gt;
  
  
  What is Bull?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bull&lt;/strong&gt; is a job and message queue built for Node.js. It uses &lt;strong&gt;Redis&lt;/strong&gt; under the hood, which makes it:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast&lt;/strong&gt; → thanks to in-memory operations.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Durable&lt;/strong&gt; → jobs won’t just vanish if something crashes.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalable&lt;/strong&gt; → you can run multiple workers and share the load.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Out of the box, Bull gives you advanced features like retries, delayed jobs, repeat jobs, and monitoring.  &lt;/p&gt;

&lt;p&gt;Think of it as your app’s &lt;strong&gt;task manager&lt;/strong&gt; — organizing, scheduling, and making sure things get done, even if your app crashes.  &lt;/p&gt;




&lt;h2&gt;
  
  
  How Bull Works (Architecture)
&lt;/h2&gt;

&lt;p&gt;Bull revolves around a few simple building blocks:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Queue&lt;/strong&gt; → Stores jobs in Redis and manages them.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job&lt;/strong&gt; → A unit of work (like “send an email” or “generate a PDF”).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worker (Processor)&lt;/strong&gt; → A function that picks up jobs and executes them.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Events&lt;/strong&gt; → Notifications when a job completes, fails, or stalls.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Redis guarantees &lt;strong&gt;atomic operations&lt;/strong&gt;. That means jobs won’t get lost or processed twice — super important in production.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Job Lifecycle
&lt;/h2&gt;

&lt;p&gt;Every job in Bull goes through a series of states:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Created&lt;/strong&gt; → You add the job (producer creates it).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Waiting&lt;/strong&gt; → Job sits in the queue until a worker is ready.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active&lt;/strong&gt; → A worker picks it up and starts processing.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Completed or Failed&lt;/strong&gt; → Job finishes successfully or errors out.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stalled&lt;/strong&gt; → If a worker crashes midway, Bull puts the job back into the queue.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;👉 This lifecycle ensures that no jobs “silently disappear.”  &lt;/p&gt;




&lt;h2&gt;
  
  
  Core Features (Why Developers Love Bull)
&lt;/h2&gt;

&lt;p&gt;Bull comes packed with features that make it production-ready:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retries &amp;amp; Backoff&lt;/strong&gt; → Failed jobs retry automatically. You can add backoff strategies like exponential delay to avoid hammering external APIs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delayed Jobs&lt;/strong&gt; → Schedule jobs in the future (like sending a reminder 24 hours later).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeatable Jobs&lt;/strong&gt; → Run jobs on a cron schedule (like daily reports).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Priorities&lt;/strong&gt; → Important jobs (like fraud alerts) can skip the line.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limiting&lt;/strong&gt; → Control how many jobs run per second to avoid hitting API rate limits.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency&lt;/strong&gt; → Let one worker handle multiple jobs at once.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progress Updates&lt;/strong&gt; → Track job progress (like 30% done on video encoding).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Cleanup&lt;/strong&gt; → Prevent Redis from filling up by removing completed jobs.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 &lt;strong&gt;Pro Tip&lt;/strong&gt;: Combine retries + dead-letter queues to make your system both resilient and debuggable.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Operational Superpowers
&lt;/h2&gt;

&lt;p&gt;Bull takes care of a lot of tricky details for you:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detects stalled jobs automatically and requeues them.
&lt;/li&gt;
&lt;li&gt;Uses &lt;strong&gt;Lua scripts&lt;/strong&gt; to guarantee atomic operations in Redis.
&lt;/li&gt;
&lt;li&gt;Ensures jobs survive app restarts or worker crashes.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s why many devs trust Bull for critical workloads.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Configurations Made Easy
&lt;/h2&gt;

&lt;p&gt;You can fine-tune Bull at both the &lt;strong&gt;queue&lt;/strong&gt; and &lt;strong&gt;job&lt;/strong&gt; level:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Job options&lt;/strong&gt; → attempts, backoff, priority, delay.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queue options&lt;/strong&gt; → FIFO vs. LIFO processing, rate limits, global defaults.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This flexibility means you can have one queue for “emails” that retries 5 times, and another for “payments” that retries 10 times with exponential backoff.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Events &amp;amp; Hooks
&lt;/h2&gt;

&lt;p&gt;Bull emits useful events so you can plug in your own logic:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;completed&lt;/code&gt; → Job finished successfully.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;failed&lt;/code&gt; → Job failed (after retries).
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;progress&lt;/code&gt; → Worker reported progress.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stalled&lt;/code&gt; → Worker died midway.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;drained&lt;/code&gt; → No jobs left in the queue.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 These hooks are perfect for logging, monitoring, or triggering other workflows.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Monitoring Made Simple
&lt;/h2&gt;

&lt;p&gt;Observability is key. Bull integrates with tools like &lt;strong&gt;Bull Board&lt;/strong&gt; or &lt;strong&gt;Arena&lt;/strong&gt;, giving you a neat dashboard where you can:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View pending, active, completed, and failed jobs.
&lt;/li&gt;
&lt;li&gt;Retry or remove failed jobs with one click.
&lt;/li&gt;
&lt;li&gt;Monitor worker speed and error rates.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For bigger setups, you can also send metrics to &lt;strong&gt;Prometheus + Grafana&lt;/strong&gt; for full-blown monitoring.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Scaling Bull
&lt;/h2&gt;

&lt;p&gt;Scaling is straightforward:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run multiple workers consuming the same queue.
&lt;/li&gt;
&lt;li&gt;Split jobs across multiple queues (emails, payments, media processing).
&lt;/li&gt;
&lt;li&gt;Auto-scale workers in the cloud depending on queue length.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes Bull suitable for both &lt;strong&gt;small apps&lt;/strong&gt; and &lt;strong&gt;enterprise-scale systems&lt;/strong&gt;.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Best Practices for Job Data
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keep job payloads &lt;strong&gt;lightweight&lt;/strong&gt;. Don’t put raw files in Redis — store them in S3 or a DB and pass just the reference (like file path or ID).
&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;versioning&lt;/strong&gt; to job data in case your schema changes later.
&lt;/li&gt;
&lt;li&gt;Validate job data before enqueueing to prevent poison jobs.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Security &amp;amp; Reliability Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Make jobs &lt;strong&gt;idempotent&lt;/strong&gt; → running the same job twice shouldn’t cause duplication (e.g., double charges).
&lt;/li&gt;
&lt;li&gt;Don’t put raw &lt;strong&gt;sensitive data&lt;/strong&gt; (like passwords or PII) into Redis. Use references or encrypted tokens.
&lt;/li&gt;
&lt;li&gt;Clean up completed jobs regularly to keep Redis memory healthy.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Bull vs Alternatives
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BullMQ&lt;/strong&gt; → The next-gen version of Bull, better TypeScript support, more features.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agenda&lt;/strong&gt; → MongoDB-based, good for cron-like scheduling.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bree&lt;/strong&gt; → Node.js-native job scheduler, doesn’t need Redis.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQS / Kafka&lt;/strong&gt; → Heavy-duty, distributed solutions for very large systems.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 For most Node.js apps, &lt;strong&gt;Bull hits the sweet spot&lt;/strong&gt; between power and simplicity.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Common Pitfalls (Watch Out!)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redis memory bloat&lt;/strong&gt; if you don’t clean up old jobs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infinite retries&lt;/strong&gt; if misconfigured.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long-running jobs&lt;/strong&gt; may block the event loop — use child processes or workers.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Deployment Tips
&lt;/h2&gt;

&lt;p&gt;For production setups:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Redis persistence (AOF or RDB snapshots).
&lt;/li&gt;
&lt;li&gt;Set up Redis with &lt;strong&gt;replicas or cluster mode&lt;/strong&gt; for high availability.
&lt;/li&gt;
&lt;li&gt;Keep workers in the same region/close to Redis to minimize latency.
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;✅ With Bull, you don’t just get a queue — you get a &lt;strong&gt;full-fledged background job system&lt;/strong&gt; that’s reliable, scalable, and battle-tested. Whether you’re running a startup project or a large distributed system, Bull can handle it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>programming</category>
      <category>development</category>
    </item>
    <item>
      <title>Understanding Queueing in Node.js</title>
      <dc:creator>ronak navadia</dc:creator>
      <pubDate>Mon, 25 Aug 2025 17:00:06 +0000</pubDate>
      <link>https://forem.com/ronak_navadia/understanding-queueing-in-nodejs-55oi</link>
      <guid>https://forem.com/ronak_navadia/understanding-queueing-in-nodejs-55oi</guid>
      <description>&lt;h1&gt;
  
  
  Introduction to Queues in Node.js
&lt;/h1&gt;

&lt;p&gt;When you build applications in Node.js, you’ll often deal with tasks that are either time-consuming or don’t need to run immediately. For example, sending confirmation emails, generating reports, or processing uploaded images. If you try to perform such tasks directly inside your API response cycle, your server might become slow and unresponsive.&lt;/p&gt;

&lt;p&gt;This is where queueing comes into play. Let’s dive deeper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Queues?
&lt;/h2&gt;

&lt;p&gt;A queue helps in managing workloads efficiently. Instead of handling everything instantly, tasks can be lined up for processing later. This ensures that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The application doesn’t get overwhelmed during heavy traffic.&lt;/li&gt;
&lt;li&gt;Time-consuming jobs don’t block user-facing requests.&lt;/li&gt;
&lt;li&gt;The system can recover gracefully from failures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it like a restaurant: the waiter (producer) takes multiple orders and places them in a queue for the chef (consumer/worker) to prepare.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Queue?
&lt;/h2&gt;

&lt;p&gt;A queue is a &lt;strong&gt;First In, First Out (FIFO)&lt;/strong&gt; data structure. In software, it acts as a middle layer between the producer (who creates jobs) and the consumer (who processes them).&lt;/p&gt;

&lt;p&gt;For example, if five users upload files at the same time, all requests can be added to the queue. Workers then pick them one by one (or in parallel) to process without overloading the system.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Job?
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;job&lt;/strong&gt; is a unit of work inside the queue. It contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Payload&lt;/strong&gt; – the actual data required to complete the task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata&lt;/strong&gt; – such as job ID, number of retries, scheduled time, or priority.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example jobs:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;An email job may contain the recipient, subject, and body.&lt;/li&gt;
&lt;li&gt;A video processing job may contain the file path and encoding settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jobs help break down complex workloads into manageable pieces.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Job Producer?
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;producer&lt;/strong&gt; is the part of the system that creates and submits jobs to the queue. This is usually your application server or API layer.&lt;/p&gt;

&lt;p&gt;Example: When a user signs up, your API endpoint can immediately return a response while also creating a “send welcome email” job and placing it into the queue. The actual email sending will happen later by a worker.&lt;/p&gt;

&lt;p&gt;This ensures responsiveness and prevents delays in user interactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Worker (Job Consumer)?
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;worker&lt;/strong&gt; (or consumer) is a dedicated process that continuously listens to the queue and executes jobs as they arrive.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple workers can run in parallel to handle higher loads.&lt;/li&gt;
&lt;li&gt;Workers can retry failed jobs or handle errors gracefully.&lt;/li&gt;
&lt;li&gt;They’re often separated from the main server to avoid blocking real-time traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: An “email worker” continuously checks the queue for email jobs and sends them using an SMTP service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Queues?
&lt;/h2&gt;

&lt;p&gt;Queues are useful for several reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reliability&lt;/strong&gt;: If a worker crashes, the job remains safe in the queue and will be retried.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: You can add more workers as your workload increases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Heavy tasks don’t slow down your main application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: Producers and consumers don’t need to know about each other’s implementation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without queues, you risk slower responses, timeouts, and lost jobs during failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Use Cases
&lt;/h2&gt;

&lt;p&gt;Queues are everywhere in modern applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending bulk notifications (emails, SMS, push messages).&lt;/li&gt;
&lt;li&gt;Image/video processing in the background.&lt;/li&gt;
&lt;li&gt;Handling third-party API requests that may be slow.&lt;/li&gt;
&lt;li&gt;Managing scheduled tasks like billing, reports, or reminders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, anything that can be done later should go into a queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Queue Features (In Depth)
&lt;/h2&gt;

&lt;p&gt;Modern queue systems provide powerful features that go beyond simple FIFO processing:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Delayed Jobs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Execute after a specific time.&lt;/li&gt;
&lt;li&gt;Example: “Send password reset reminder email 30 minutes later.”&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Scheduled/Recurring Jobs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Run jobs at fixed intervals using cron expressions.&lt;/li&gt;
&lt;li&gt;Example: “Generate sales reports every midnight.”&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Priority Jobs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;High-priority jobs jump ahead of others in the queue.&lt;/li&gt;
&lt;li&gt;Example: “Fraud alerts” take precedence over “weekly newsletters.”&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Concurrency
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multiple jobs can be processed simultaneously by the same worker.&lt;/li&gt;
&lt;li&gt;Example: A worker handling 10 image-processing jobs in parallel.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Rate Limiting &amp;amp; Throttling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Restrict how many jobs run in a given time frame.&lt;/li&gt;
&lt;li&gt;Example: Call a third-party API only 100 times per minute to avoid rate-limit errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Job Progress &amp;amp; Events
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Workers can update job status (e.g., 30% done).&lt;/li&gt;
&lt;li&gt;Example: Tracking progress of a video upload and transcoding.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These features make queues versatile and capable of handling real-world workloads gracefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reliability Patterns (Making Queues Robust)
&lt;/h2&gt;

&lt;p&gt;Queues must be resilient to failures, otherwise they create more problems than they solve. Some common patterns are:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Acknowledgements (ACKs)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A job is marked complete only when a worker explicitly acknowledges success.&lt;/li&gt;
&lt;li&gt;Prevents job loss if a worker crashes mid-task.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Retries with Backoff
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Failed jobs are retried automatically with increasing delays.&lt;/li&gt;
&lt;li&gt;Example: Retry after 5s, then 15s, then 1 minute, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Dead-letter Queues (DLQ)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Jobs that fail after multiple retries are moved to a separate queue.&lt;/li&gt;
&lt;li&gt;Example: “Invalid email addresses” jobs end up in DLQ for manual review.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Idempotency
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Jobs are designed so running them multiple times doesn’t cause duplicate effects.&lt;/li&gt;
&lt;li&gt;Example: A billing system checks if a payment is already processed before charging again.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Job Deduplication
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prevents enqueueing the same job multiple times.&lt;/li&gt;
&lt;li&gt;Example: Avoid sending multiple welcome emails if a user triggers signup twice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These patterns ensure that even in the face of crashes, network errors, or bad data, your system stays consistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observability (Monitoring Queues)
&lt;/h2&gt;

&lt;p&gt;A queue without monitoring is like flying blind. You should always track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Job States&lt;/strong&gt; – pending, active, completed, failed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worker Metrics&lt;/strong&gt; – how fast workers process jobs, average latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure Rates&lt;/strong&gt; – recurring errors often signal bugs or bad data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput&lt;/strong&gt; – number of jobs processed per second/minute.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools like Bull Board, Arena, or custom dashboards give real-time visibility into job lifecycles. Alerts and logs can notify you of unusual delays or spikes in failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotchas (Challenges with Queues)
&lt;/h2&gt;

&lt;p&gt;While queues are powerful, they come with challenges:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Poison Jobs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A job with invalid data keeps failing forever.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix&lt;/strong&gt;: Use dead-letter queues and validation before enqueueing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Duplicate Jobs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Same work gets queued multiple times accidentally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix&lt;/strong&gt;: Add deduplication keys or job uniqueness constraints.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Ordering vs Parallelism
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Running jobs in parallel can cause them to complete out of order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix&lt;/strong&gt;: Use priority queues or partitioning for strict ordering needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Resource Starvation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A few heavy jobs might block lightweight ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix&lt;/strong&gt;: Split queues by type (e.g., email queue vs. video processing queue).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When Not to Use Queues
&lt;/h2&gt;

&lt;p&gt;Queues aren’t always necessary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For very small apps, queues add unnecessary complexity.&lt;/li&gt;
&lt;li&gt;For real-time tasks (like “user is typing” indicators in chat), queues introduce unwanted delays.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use queues when they truly solve a scalability or reliability issue.&lt;/p&gt;

&lt;p&gt;If you're interested in learning more about bulls and how they can be used in various contexts like task queues, job management, and real-time systems, check out our detailed post on &lt;a href="https://tinyurl.com/u3uj77fk" rel="noopener noreferrer"&gt;Bull: The Robust Job and Queue System.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>programming</category>
      <category>development</category>
    </item>
    <item>
      <title>Setting Up ESLint and Prettier in a Node.js Project: A Complete Guide.</title>
      <dc:creator>ronak navadia</dc:creator>
      <pubDate>Sun, 11 May 2025 17:30:10 +0000</pubDate>
      <link>https://forem.com/ronak_navadia/setting-up-eslint-and-prettier-in-a-nodejs-project-a-complete-guide-4a9d</link>
      <guid>https://forem.com/ronak_navadia/setting-up-eslint-and-prettier-in-a-nodejs-project-a-complete-guide-4a9d</guid>
      <description>&lt;p&gt;Have you ever worked on a project where quotes were sometimes single, sometimes double? Where some files used semicolons and others didn't? Or worse, have you ever spent hours debugging because you used a variable that wasn't imported? If you answer yes to any of these questions, this guide is for you!&lt;/p&gt;

&lt;p&gt;In this blog post, I'll walk you through setting up ESLint and Prettier in your Node.js project in simple, easy-to-follow steps. I'll explain what each tool does, why you need it, and how to configure it properly - all in plain language that anyone can understand.&lt;/p&gt;




&lt;h2&gt;
  
  
  What are ESLint and Prettier?
&lt;/h2&gt;

&lt;p&gt;Before diving into the setup, let's understand what these tools do:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ESLint&lt;/strong&gt; is like a code detective. It checks your code for potential errors and enforces coding style rules. For example, it can warn you if you're using a variable that hasn't been defined, or if you're not following the project's coding standards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prettier&lt;/strong&gt; is like an automatic code formatter. It takes your code, regardless of how it's formatted, and makes it look consistent according to the rules you set. It handles things like indentation, spacing, and line breaks.&lt;/p&gt;

&lt;p&gt;Together, these tools help make your code more consistent, easier to read, and less prone to bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Do I Need These Tools?
&lt;/h2&gt;

&lt;p&gt;You might be wondering, "Why bother with all this setup?" Here are a few real-world problems these tools solve:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Catching errors before they happen&lt;/strong&gt;: ESLint can spot potential bugs before you even run your code.&lt;br&gt;
&lt;strong&gt;Consistency across projects&lt;/strong&gt;: No more debating whether to use tabs or spaces, or single or double quotes.&lt;br&gt;
&lt;strong&gt;Saving time&lt;/strong&gt;: Instead of manually formatting your code, Prettier does it for you instantly.&lt;br&gt;
&lt;strong&gt;Improved collaboration&lt;/strong&gt;: Everyone on the team follows the same coding standards automatically.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step-by-Step Setup Guide
&lt;/h2&gt;

&lt;p&gt;Let's break down the process into simple steps:&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Install the Required Packages
&lt;/h2&gt;

&lt;p&gt;First, we need to install ESLint, Prettier, and some helper packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; eslint prettier eslint-config-prettier eslint-plugin-import globals
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What each package does:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;eslint&lt;/strong&gt;: The main linting tool that checks your code for problems&lt;br&gt;
&lt;strong&gt;prettier&lt;/strong&gt;: The code formatter that makes your code look consistent&lt;br&gt;
&lt;strong&gt;eslint-config-prettier&lt;/strong&gt;: Turns off ESLint rules that might conflict with Prettier&lt;br&gt;
&lt;strong&gt;eslint-plugin-import&lt;/strong&gt;: Helps ESLint check import/export statements (super helpful!)&lt;br&gt;
&lt;strong&gt;globals&lt;/strong&gt;: Provides global variables for different environments (like Node.js)&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Create Configuration Files
&lt;/h2&gt;

&lt;p&gt;Next, we need to create configuration files for ESLint and Prettier.&lt;/p&gt;

&lt;p&gt;**ESLint Configuration (eslint.config.js)&lt;/p&gt;

&lt;p&gt;This file tells ESLint how to check your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;eslint&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@eslint/js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;prettierConfig&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint-config-prettier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;importPlugin&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint-plugin-import&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;globals&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;globals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;configs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;recommended&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**/*.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;languageOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;ecmaVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;latest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sourceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;es2021&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;import&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;importPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Enforce import/export syntax&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;import/no-unresolved&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;import/named&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;import/default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;import/export&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="c1"&gt;// Prevent usage of variables before they are defined&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-use-before-define&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="c1"&gt;// Enforce consistent quote style (single quotes)&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;quotes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;single&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;avoidEscape&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;

      &lt;span class="c1"&gt;// Require semicolons&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;semi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;

      &lt;span class="c1"&gt;// Disallow unused variables&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-unused-vars&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;argsIgnorePattern&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;^_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;prettierConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;**Key points about this config:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's set up for modern JavaScript using ES modules&lt;/li&gt;
&lt;li&gt;It adds specific rules to catch missing imports&lt;/li&gt;
&lt;li&gt;It enforces style rules like single quotes and semicolons&lt;/li&gt;
&lt;li&gt;It includes Node.js globals, so you won't get errors about &lt;code&gt;console&lt;/code&gt; or &lt;code&gt;process&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;**Prettier Configuration (.prettierrc)&lt;br&gt;
This file tells Prettier how to format your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"singleQuote"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trailingComma"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"es5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"semi"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tabWidth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"printWidth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bracketSpacing"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"arrowParens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"avoid"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses single quotes instead of double quotes&lt;/li&gt;
&lt;li&gt;Adds semicolons at the end of statements&lt;/li&gt;
&lt;li&gt;Sets tab width to 2 spaces&lt;/li&gt;
&lt;li&gt;Limits line length to 100 characters&lt;/li&gt;
&lt;li&gt;Adds spaces inside brackets&lt;/li&gt;
&lt;li&gt;Avoids parentheses around single arrow function parameters&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Set Up Editor Integration
&lt;/h2&gt;

&lt;p&gt;To make ESLint and Prettier work seamlessly with your code editor, we need to add some editor-specific settings.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.vscode&lt;/code&gt; folder in your project root, then add a &lt;code&gt;settings.json&lt;/code&gt; file inside it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.formatOnSave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.codeActionsOnSave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"source.fixAll.eslint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eslint.validate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"javascript"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prettier.singleQuote"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells VS Code to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Format your code automatically when you save&lt;/li&gt;
&lt;li&gt;Use Prettier as the default formatter&lt;/li&gt;
&lt;li&gt;Fix ESLint issues automatically when you save&lt;/li&gt;
&lt;li&gt;Apply ESLint to JavaScript files&lt;/li&gt;
&lt;li&gt;Use single quotes with Prettier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;**For Cursor:&lt;br&gt;
Since Cursor is built on VS Code, the same settings work there too! Just create the same .vscode folder and settings.json file.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4: Install Editor Extensions
&lt;/h2&gt;

&lt;p&gt;To make everything work smoothly, install these extensions in your editor:&lt;/p&gt;

&lt;p&gt;**For VS Code or Cursor:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ESLint (by Microsoft)&lt;/li&gt;
&lt;li&gt;Prettier - Code formatter (by Prettier)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can install them from the Extensions marketplace in your editor.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5: Add NPM/Yarn Scripts
&lt;/h2&gt;

&lt;p&gt;Add these scripts to your package.json file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eslint . --ext .js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lint:fix&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eslint . --ext .js --fix&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;format&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prettier --write .&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These scripts let you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check your code for issues (&lt;code&gt;yarn lint&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Fix linting issues automatically (&lt;code&gt;yarn lint:fix&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Format your entire project (&lt;code&gt;yarn format&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing Your Setup
&lt;/h2&gt;

&lt;p&gt;To make sure everything is working correctly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a test file with some issues:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This should show an error (missing import)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;someFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// This should be converted to single quotes&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This should be converted to single quotes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// This should show an unused variable warning&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unusedVar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save the file and check if:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;ESLint highlights the errors
&lt;/li&gt;
&lt;li&gt;The quotes are automatically converted to single quotes
&lt;/li&gt;
&lt;li&gt;The indentation and formatting are fixed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Setting up ESLint and Prettier might seem like extra work at first, but it pays off enormously in the long run. Your code will be more consistent, you'll catch errors earlier, and you'll spend less time on formatting and style issues.&lt;/p&gt;

&lt;p&gt;The configuration we've set up in this guide is particularly useful for Node.js projects using ES modules, but you can easily adapt it for other types of projects by adjusting the rules and plugins.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;P.S. If you ever need to reference this setup again, bookmark this blog post or save the configuration files in a GitHub repository for easy access!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Complete Beginner’s Guide to Git: Setup, SSH, Tokens, Remotes, and More.</title>
      <dc:creator>ronak navadia</dc:creator>
      <pubDate>Sun, 11 May 2025 15:45:04 +0000</pubDate>
      <link>https://forem.com/ronak_navadia/the-complete-beginners-guide-to-git-setup-ssh-tokens-remotes-and-more-2hca</link>
      <guid>https://forem.com/ronak_navadia/the-complete-beginners-guide-to-git-setup-ssh-tokens-remotes-and-more-2hca</guid>
      <description>&lt;p&gt;If you’re learning development, sooner or later you'll hear everyone saying “use Git!”&lt;br&gt;
But no one really stops to explain it like a normal human being.&lt;/p&gt;

&lt;p&gt;Let's fix that.&lt;/p&gt;

&lt;p&gt;This post is your no-jargon, no-overcomplicated guide to Git.&lt;br&gt;
We’ll start with what Git is, why you need it, and how to set it up properly — even covering the small details like SSH vs HTTPS vs Tokens.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Git?(Magic Time Machine for Your Code)
&lt;/h2&gt;

&lt;p&gt;Imagine you're writing a story and want to save versions as you go—so you can look back or undo changes. Git does that for coding projects.&lt;/p&gt;

&lt;p&gt;🔧 Definition:&lt;br&gt;
Git is a version control system. It tracks changes, helps you work with others, and lets you go back to earlier versions of your files.&lt;/p&gt;

&lt;p&gt;🧠 Why Use Git?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track changes over time&lt;/li&gt;
&lt;li&gt;Collaborate without conflicts&lt;/li&gt;
&lt;li&gt;Experiment safely in branches&lt;/li&gt;
&lt;li&gt;Backup your work using platforms like GitHub&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub&lt;/p&gt;

&lt;p&gt;📘 Example:&lt;br&gt;
On Monday: &lt;code&gt;&amp;lt;h1&amp;gt;Hello World&amp;lt;/h1&amp;gt;&lt;/code&gt;&lt;br&gt;
On Tuesday: &lt;code&gt;&amp;lt;h1&amp;gt;Welcome to My Website&amp;lt;/h1&amp;gt;&lt;/code&gt;&lt;br&gt;
With Git, you can easily switch between these versions and see what changed.&lt;/p&gt;

&lt;p&gt;🖥️ How It Works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start with &lt;code&gt;git init&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Save changes using &lt;code&gt;git commit&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Upload to GitHub using &lt;code&gt;git push&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  What is GitHub, GitLab, Bitbucket? (Code Banks)
&lt;/h2&gt;

&lt;p&gt;Git is only local by default — like saving your essay on your personal laptop.&lt;/p&gt;

&lt;p&gt;But what if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want a backup in case your laptop crashes?&lt;/li&gt;
&lt;li&gt;You want to share it with friends across the world?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You need an online bank for your code like GitHub, GitLab, Bitbucket&lt;/p&gt;

&lt;p&gt;Think of GitHub / GitLab / Bitbucket as Google Drive for Code.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GitHub – The most widely used, great for open source and teams. Features include issues, pull requests, and GitHub Actions for automation.&lt;/li&gt;
&lt;li&gt;GitLab – Offers Git hosting plus built-in DevOps tools like CI/CD. Great for teams wanting an all-in-one solution.&lt;/li&gt;
&lt;li&gt;Bitbucket – Made by Atlassian (creators of Jira), it’s ideal for teams already using Jira or Trello. Includes Bitbucket Pipelines for CI/CD.&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  How to Set Up Git on Your Local Machine (Step-by-Step)
&lt;/h2&gt;

&lt;p&gt;🖥️ &lt;strong&gt;Step 1&lt;/strong&gt;: Install Git&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows: Download from git-scm.com and run the installer (default settings are fine). Open Git Bash after install.&lt;/li&gt;
&lt;li&gt;macOS: Run git in Terminal—macOS will prompt you to install Xcode CLI tools.&lt;/li&gt;
&lt;li&gt;Linux:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update  
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;git  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;🧪 Check Git Version&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nt"&gt;--version&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚙️ &lt;strong&gt;Step 2&lt;/strong&gt;: Set Your Identity&lt;br&gt;
Tell Git who you are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.name &lt;span class="s2"&gt;"Your Name"&lt;/span&gt;  
git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.email &lt;span class="s2"&gt;"you@example.com"&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check settings with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--list&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📁 &lt;strong&gt;Step 3&lt;/strong&gt;: Initialize Git&lt;br&gt;
In your project folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;your/project/path  
git init  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📝 &lt;strong&gt;Step 4&lt;/strong&gt;: Make Your First Commit&lt;br&gt;
Create a file (e.g., index.html), then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add index.html  
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit"&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Your project is now tracked by Git!&lt;/p&gt;

&lt;p&gt;🔍 Optional: Local Git Config vs Global Git Config&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--global: Applies settings to all projects on your computer.&lt;/li&gt;
&lt;li&gt;(No --global): Applies settings only to the current project (inside that .git folder).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config user.email &lt;span class="s2"&gt;"another@example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only applies to the current project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding What Remote and Origin in Git is.
&lt;/h2&gt;

&lt;p&gt;🌐 What’s a Remote?&lt;br&gt;
When you use Git on your computer, everything is local. But to share or back up your project online (like on GitHub), you need to connect it to a remote.&lt;/p&gt;

&lt;p&gt;🛰️ Remote = Online version of your project&lt;br&gt;
When you run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’re saying: “Send my changes to the remote.”&lt;/p&gt;

&lt;p&gt;When you run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git pull  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’re saying: “Get the latest changes from the remote.”&lt;/p&gt;

&lt;p&gt;🔖 What is origin?&lt;br&gt;
When you first connect your local project to a remote, Git gives it a default name:&lt;br&gt;
origin = nickname for your main remote (you can rename it, but "origin" is the standard).&lt;/p&gt;

&lt;p&gt;🧪 Example: Connect to GitHub&lt;br&gt;
If your GitHub repo is:&lt;br&gt;
&lt;a href="https://github.com/yourname/myproject.git" rel="noopener noreferrer"&gt;https://github.com/yourname/myproject.git&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Connect it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin https://github.com/yourname/myproject.git  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now push your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔍 View Remotes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote &lt;span class="nt"&gt;-v&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔄 Multiple Remotes? No problem.&lt;br&gt;
You can add more:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add github https://github.com/you/repo.git  
git remote add gitlab https://gitlab.com/you/repo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Push to each one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push github main  
git push gitlab main  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Understanding the Difference Between HTTPS and SSH URLs in Git
&lt;/h2&gt;

&lt;p&gt;When connecting your local Git project to GitHub (or similar), you'll see two types of URLs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTPS: &lt;a href="https://github.com/yourname/repo.git" rel="noopener noreferrer"&gt;https://github.com/yourname/repo.git&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SSH: &lt;a href="mailto:git@github.com"&gt;git@github.com&lt;/a&gt;:yourname/repo.git&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both work, but they connect differently.&lt;/p&gt;

&lt;p&gt;🔐 HTTPS&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses your username + token to authenticate&lt;/li&gt;
&lt;li&gt;Easy to set up—no special tools or keys&lt;/li&gt;
&lt;li&gt;But you might have to enter your token often (unless cached)&lt;/li&gt;
&lt;li&gt;GitHub doesn’t allow plain passwords anymore&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🛡️ SSH&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses a public/private key pair (no password after setup)&lt;/li&gt;
&lt;li&gt;Takes a bit more time to set up&lt;/li&gt;
&lt;li&gt;More secure and seamless for daily use&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What is SSH? And How to Set It Up for Git (Step-by-Step)
&lt;/h2&gt;

&lt;p&gt;🔐 What is SSH (Simple Version)&lt;br&gt;
SSH (Secure Shell) is a safe way for your computer to connect to services like GitHub without needing to type your password every time.&lt;/p&gt;

&lt;p&gt;Instead of logging in manually, you use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public Key → Added to GitHub/GitLab/etc.&lt;/li&gt;
&lt;li&gt;Private Key → Stays on your computer and proves your identity automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's like using a digital key to unlock the door without knocking.&lt;/p&gt;

&lt;p&gt;🛠️ Set Up SSH for Git (Quick Steps)&lt;br&gt;
✅ 1. Check for existing keys:&lt;/p&gt;

&lt;p&gt;Windows (Git Bash):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-al&lt;/span&gt; ~/.ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows (PowerShell):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Get-ChildItem &lt;span class="nt"&gt;-Path&lt;/span&gt; &lt;span class="nv"&gt;$env&lt;/span&gt;:USERPROFILE&lt;span class="se"&gt;\.&lt;/span&gt;ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows (CMD):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;dir&lt;/span&gt; %USERPROFILE%&lt;span class="se"&gt;\.&lt;/span&gt;ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;macOS / Linux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-al&lt;/span&gt; ~/.ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔐 2. Generate a new key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"your_email@example.com"&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Press Enter through prompts. It creates two files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private key: ~/.ssh/id_ed25519 (keep safe)&lt;/li&gt;
&lt;li&gt;Public key: ~/.ssh/id_ed25519.pub (share)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚀 3. Add your key to the SSH agent:&lt;br&gt;
The SSH agent is a background program that securely holds your SSH key in memory, so you don’t have to re-enter your passphrase every time you use Git. It makes authentication seamless and more secure during your session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;ssh-agent &lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;  
ssh-add ~/.ssh/id_ed25519  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🌐 4. Add your public key to your Git host:&lt;br&gt;
Show the key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_ed25519.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the output and paste it into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub → Settings → SSH Keys&lt;/li&gt;
&lt;li&gt;GitLab → Preferences → SSH Keys&lt;/li&gt;
&lt;li&gt;Bitbucket → Personal Settings → SSH Keys&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔍 5. Test your connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-T&lt;/span&gt; git@github.com  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see:&lt;br&gt;
“Hi username! You've successfully authenticated...”&lt;/p&gt;


&lt;h2&gt;
  
  
  Different Ways to Connect Git with Online Services (GitHub, GitLab, Bitbucket)
&lt;/h2&gt;

&lt;p&gt;🔹 Connecting Git Using Username and Password (Only on GitLab and Bitbucket)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚫 GitHub no longer allows username + password for Git over HTTPS.&lt;br&gt;
✅ This still works on GitLab and Bitbucket (for now), but is considered less secure&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;br&gt;
You clone the repo using the HTTPS URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://gitlab.com/username/project.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you push:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git will prompt you to enter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your username&lt;/li&gt;
&lt;li&gt;Your password&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 You can cache these credentials using Git Credential Manager (on Windows/macOS) or helper scripts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why avoid it?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easily forgettable.&lt;/li&gt;
&lt;li&gt;Passwords can be compromised.&lt;/li&gt;
&lt;li&gt;Many platforms are moving away from this for security reasons.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔹 b. Connecting Git Using SSH (Recommended Method)&lt;br&gt;
**How it works:&lt;br&gt;
You clone the repo using the SSH URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@gitlab.com:username/project.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your SSH key is automatically used to authenticate (no username or password prompts).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✅ Secure and fast once set up.&lt;br&gt;
🔁 Works well for frequent Git users or developers managing many projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;🔹 c. Connecting Git Using Personal Access Token (PAT)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔐 GitHub requires a Personal Access Token (PAT) for HTTPS connections.&lt;br&gt;
GitLab and Bitbucket support PATs as an alternative to passwords.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generate a token from your Git platform:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/settings/tokens" rel="noopener noreferrer"&gt;https://github.com/settings/tokens&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitLab: User → Preferences → Access Tokens
&lt;/li&gt;
&lt;li&gt;Bitbucket: Personal Settings → Access Management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use HTTPS to clone the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/yourusername/project.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Username: your GitHub/GitLab username&lt;/li&gt;
&lt;li&gt;Password: your access token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 You can use a credential helper to cache the token so you don’t retype it every time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; credential.helper cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Handling Multiple Git Accounts on the Same Device
&lt;/h2&gt;

&lt;p&gt;If you work with more than one GitHub, GitLab, or Bitbucket account (e.g., one personal and one work), things can get tricky.&lt;/p&gt;

&lt;p&gt;Here’s how to manage multiple accounts without mixing them up.&lt;/p&gt;

&lt;p&gt;✅ Method 1: Use SSH with Separate Keys for Each Account&lt;br&gt;
Generate a second SSH key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"you@work-email.com"&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ~/.ssh/id_ed25519_work
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add it to the SSH agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-add ~/.ssh/id_ed25519_work
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the public key to your second Git account (e.g., work GitHub/GitLab).&lt;/p&gt;

&lt;p&gt;Edit ~/.ssh/config to tell Git which key to use for each domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Personal GitHub&lt;/span&gt;
Host github.com-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519

&lt;span class="c"&gt;# Work GitHub&lt;/span&gt;
Host github.com-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_work

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone using custom hostname:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com-work:workuser/project.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your local repo, set the correct remote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote set-url origin git@github.com-work:workuser/project.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Method 2: Use HTTPS + Git Credential Manager (Separate Git Identities)&lt;br&gt;
You can also manage multiple accounts by:&lt;/p&gt;

&lt;p&gt;Setting per-project Git identities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config user.name &lt;span class="s2"&gt;"Work Name"&lt;/span&gt;
git config user.email &lt;span class="s2"&gt;"work@example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using Git Credential Manager (built-in on Windows/macOS) to store different credentials per URL.&lt;/p&gt;

&lt;p&gt;🧾 Wrapping Up&lt;br&gt;
Getting started with Git and remote repositories might feel a bit technical at first, but once you understand the core concepts—like what Git is, how remotes work, and the difference between HTTPS and SSH—it becomes second nature.&lt;/p&gt;

&lt;p&gt;Whether you're a solo developer or working in a team, properly setting up Git and knowing how to securely connect to platforms like GitHub, GitLab, or Bitbucket will save you time and headaches down the road.&lt;/p&gt;

&lt;p&gt;Now that you've got the essentials down, you're ready to collaborate, contribute, and code with confidence.&lt;/p&gt;

&lt;p&gt;Happy committing! 🚀&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Getting Started with Node.js: Understanding Node, npm, nvm, and npx (and How to Install Node.js)</title>
      <dc:creator>ronak navadia</dc:creator>
      <pubDate>Sun, 20 Apr 2025 10:30:58 +0000</pubDate>
      <link>https://forem.com/ronak_navadia/getting-started-with-nodejs-understanding-node-npm-nvm-and-npx-and-how-to-install-nodejs-1dc4</link>
      <guid>https://forem.com/ronak_navadia/getting-started-with-nodejs-understanding-node-npm-nvm-and-npx-and-how-to-install-nodejs-1dc4</guid>
      <description>&lt;p&gt;When you first hear about Node.js, it's easy to feel overwhelmed with all the extra terms like npm, nvm, and npx flying around.&lt;br&gt;
Don't worry — by the end of this post, you'll not only know what each of them means, but you'll also know why they exist and how they fit together.&lt;/p&gt;

&lt;p&gt;Let's break it down, in the simplest way possible.&lt;/p&gt;


&lt;h2&gt;
  
  
  What is Node (or Node.js)?
&lt;/h2&gt;

&lt;p&gt;Imagine you have a sports car (JavaScript) — but it's stuck inside a racetrack (the browser).&lt;br&gt;
You can only drive it inside that track.&lt;/p&gt;

&lt;p&gt;Now, what if you wanted to drive it on highways, through cities, anywhere you like?&lt;/p&gt;

&lt;p&gt;Node.js is like building a powerful engine that lets JavaScript drive outside the racetrack — on the entire internet! 🚗💨&lt;/p&gt;

&lt;p&gt;In technical terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js allows JavaScript to run outside a web browser.&lt;/li&gt;
&lt;li&gt;It’s built on Google Chrome’s V8 engine, which makes it very fast.&lt;/li&gt;
&lt;li&gt;With Node.js, you can create servers, tools, APIs, scripts, and even desktop apps — all using JavaScript.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;In short: Node.js takes JavaScript from the browser to the real world.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  What is npm?
&lt;/h2&gt;

&lt;p&gt;Alright, now that you have your sports car (JavaScript with Node.js), you realize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"I need a GPS."&lt;/li&gt;
&lt;li&gt;"I want better tires."&lt;/li&gt;
&lt;li&gt;"I need fancy headlights."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Are you going to build all of that from scratch?&lt;br&gt;
Of course not!&lt;br&gt;
You’ll go to a shop and buy those accessories.&lt;/p&gt;

&lt;p&gt;npm is that shop 🛒 — but for code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;npm (Node Package Manager) is a marketplace where developers share reusable pieces of code (called "packages").&lt;/li&gt;
&lt;li&gt;You can install these packages into your project in seconds instead of building everything yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
Want to send emails in your app? Instead of coding it manually, you can just install an email package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install nodemailer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it's ready to use!&lt;br&gt;
Over 2 million packages are available on npm — everything you can imagine.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In short: npm is the world's largest supermarket for ready-made JavaScript tools.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  What is nvm?
&lt;/h2&gt;

&lt;p&gt;Imagine now that you have two cars 🚗:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One is for racing.&lt;/li&gt;
&lt;li&gt;One is for everyday driving.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can’t use racing tires on city roads — you need different setups depending on the situation.&lt;/p&gt;

&lt;p&gt;Similarly, different projects may need different Node.js versions.&lt;br&gt;
Some old projects work only on Node.js 14, but new ones need Node.js 20.&lt;/p&gt;

&lt;p&gt;nvm (Node Version Manager) is like your car garage — it lets you easily switch between different Node engines whenever needed.&lt;/p&gt;

&lt;p&gt;Using nvm, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install multiple Node versions on your system.&lt;/li&gt;
&lt;li&gt;Switch between them instantly.&lt;/li&gt;
&lt;li&gt;Test if your app works on different versions.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nvm install 16   # installs Node.js 16
nvm install 20   # installs Node.js 20
nvm use 16       # switches to Node.js 16
nvm use 20       # switches to Node.js 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Without &lt;code&gt;nvm&lt;/code&gt;, switching versions would be a real headache.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In short: nvm is your personal garage manager for different Node.js engines.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  What is npx?
&lt;/h2&gt;

&lt;p&gt;Now, back to our sports car analogy 🏎️ —&lt;br&gt;
Sometimes, you just want to test drive a car without buying it.&lt;/p&gt;

&lt;p&gt;npx is like a test drive for npm packages.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;npx lets you run any package directly without permanently installing it.&lt;/li&gt;
&lt;li&gt;It’s useful when you need a tool just once.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
You want to create a new React app, but you don’t want to install the &lt;code&gt;create-react-app&lt;/code&gt; tool permanently.&lt;/p&gt;

&lt;p&gt;Just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It downloads and runs create-react-app temporarily, and then cleans up.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In short: npx lets you borrow a tool for a quick ride without putting it in your garage.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Different Ways to Install Node.js
&lt;/h2&gt;

&lt;p&gt;Now that you understand the players (Node, npm, nvm, npx), let's talk about how you can install Node.js on your machine.&lt;/p&gt;




&lt;p&gt;Installing Node.js on Windows&lt;br&gt;
Option 1: Direct Install (Simple but not flexible)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visit &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;https://nodejs.org/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Download the LTS (Long Term Support) version.&lt;/li&gt;
&lt;li&gt;Run the installer and click "Next" → "Next" → "Install."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It will install both Node.js and npm automatically.&lt;/p&gt;

&lt;p&gt;You can check installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node -v
npm -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Good for beginners. ❌ Bad if you later need multiple Node.js versions.&lt;/p&gt;

&lt;p&gt;Option 2: Install Node.js using nvm for Windows (Recommended)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download nvm-setup.exe.&lt;/li&gt;
&lt;li&gt;Install nvm (very easy setup).&lt;/li&gt;
&lt;li&gt;Use it to install Node.js versions:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nvm install 18.16.0
nvm use 18.16.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Good for future-proofing (manage different versions). ✅ Easy switching between Node versions. ✅ Cleaner system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Installing Node.js on Ubuntu (Linux)
&lt;/h2&gt;

&lt;p&gt;Option 1: Install from Ubuntu’s Software Repo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update
sudo apt install nodejs npm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ Warning:&lt;/p&gt;

&lt;p&gt;Ubuntu’s repo may give you an outdated version.&lt;/p&gt;




&lt;p&gt;Option 2: Install Latest Node.js from NodeSource&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Gets you the latest stable version. ✅ Comes with npm.&lt;/p&gt;




&lt;p&gt;Option 3: Install Using nvm (Best Way)&lt;/p&gt;

&lt;p&gt;First, install nvm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install Node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nvm install 18
nvm use 18
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Best for flexibility. ✅ Lets you manage Node versions easily.&lt;/p&gt;




&lt;p&gt;Quick Commands Checklist After Installation&lt;/p&gt;

&lt;p&gt;After installing Node.js, verify everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node -v    # See Node.js version
npm -v     # See npm version
npx -v     # See npx version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If these commands work, you’re all set! 🎉&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Node.js has completely changed how developers use JavaScript —&lt;br&gt;
From front-end only, to building full applications, websites, servers, APIs, and even real-time apps (like chat apps)!&lt;/p&gt;

&lt;p&gt;If you're starting out — mastering Node, npm, nvm, and npx will unlock endless possibilities in your development journey 🚀.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
