Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Building a Nepal Job Portal from Scratch

By Kokil Thapa | Last reviewed: August 2026

Building a Nepal Job Portal from Scratch is fundamentally an exercise in managing high-volume, time-sensitive content rather than just coding a CRUD application. The primary challenge isn't displaying a list of vacancies; it is architecting a system that handles thousands of expiring listings, integrates local payment gateways like eSewa or Khalti for employer credits, and maintains indexability for Google without collapsing under duplicate content penalties. If you are planning this build in 2026, you need a stack that balances rapid feature iteration with strict performance budgets, typically Laravel 12 on PHP 8.4 backed by MySQL 8.4 and Redis.

How do you architect the database schema for a Nepal-specific job portal?

The most common mistake when building database-driven websites in Nepal is treating a job portal like a standard blog. Jobs have lifecycles: they are drafted, published, featured, expired, archived, and deleted. Your schema must reflect this state machine explicitly to support both user experience and search engine crawling.

In my experience shipping directory and listing platforms, a normalized schema prevents data integrity issues as volume grows. You need separate tables for employers, jobs, applications, and transactions. Crucially, for the Nepal market, you must account for variable salary formats (monthly vs. annual, NPR vs. USD) and location hierarchies that go beyond simple city names.

Employersid, company_namepan_number, verifiedcredit_balanceJobsid, employer_id (FK)title, slug, descriptionsalary_min, salary_maxexpires_at, statuslocation_districtApplicationsid, job_id (FK)candidate_email, cv_pathstatus, cover_letterTransactionsid, employer_id (FK)gateway (esewa/khalti)amount, txn_id, status1:N1:NN:1
Core database relationships for a Nepal job portal: Employers link to Jobs and Transactions, while Jobs link to Applications. Note the inclusion of PAN verification and local gateway fields essential for the Nepali market.

For salary storage, never use a single string field. Store salary_min and salary_max as unsigned integers representing NPR. This allows filtering ("Jobs above Rs 50,000") and aggregation. Display formatting happens at the view layer. For locations, create a districts table referencing Nepal’s 77 districts rather than free-text input. This standardization powers faceted search and prevents "Ktm", "Kathmandu", and "KTM" from fragmenting your results.

// Migration excerpt for jobs table (Laravel 12 / PHP 8.4)
Schema::create('jobs', function (Blueprint $table) {
    $table->id();
    $table->foreignId('employer_id')->constrained()->cascadeOnDelete();
    $table->string('title');
    $table->string('slug')->unique();
    $table->text('description');
    $table->unsignedInteger('salary_min')->nullable();
    $table->unsignedInteger('salary_max')->nullable();
    $table->enum('salary_period', ['monthly', 'annual', 'fixed'])->default('monthly');
    $table->foreignId('district_id')->constrained();
    $table->timestamp('expires_at')->index();
    $table->enum('status', ['draft', 'published', 'expired', 'filled'])->default('draft');
    $table->timestamps();
    
    // Composite index for common public queries
    $table->index(['status', 'expires_at', 'district_id']);
});

How do you integrate eSewa and Khalti payments for employer packages?

Monetizing a job portal in Nepal almost always involves selling posting credits or subscription packages to employers. International gateways like Stripe are rarely useful here because most Nepali HR departments and SMEs operate via local banking channels. You must integrate eSewa, Khalti, or ConnectIPS. I have implemented these integrations on multiple projects, and the pattern is consistent: treat every payment as an asynchronous webhook event, never as a synchronous redirect confirmation.

A common failure mode is trusting the success URL redirect. Users close tabs, networks timeout, and browsers block redirects. Your system must only grant credits when the gateway confirms the transaction via server-to-server verification. For Laravel payment integrations, create a dedicated PaymentVerificationService that handles idempotency. If eSewa sends the same webhook twice (which happens), your system should recognize the transaction_id and skip re-crediting.

  • Package Model: Create a packages table defining credit amounts, validity periods, and prices in NPR.
  • Transaction Logging: Log every API request and response to the gateway. When a client claims "I paid but credits aren't showing," you need the raw JSON response to diagnose whether it was a gateway delay or a user error.
  • Credit Ledger: Don't just update a balance column. Maintain a credit_transactions ledger (debit/credit entries) so you can audit exactly when and why credits were added or consumed.
  • Invoice Generation: Nepali businesses require VAT/PAN-compliant invoices for tax deductions. Generate PDF invoices automatically upon successful verification using a package like barryvdh/laravel-dompdf.

What technical SEO strategy prevents index bloat on job boards?

Job portals are SEO minefields. Every job listing is a unique page today but dead content tomorrow. If Google indexes 10,000 expired jobs, your crawl budget evaporates and your domain authority tanks. When conducting technical SEO audits for listing sites, I frequently see this exact problem: massive indexation of low-value, expired content.

The solution is a proactive expiration strategy combined with structured data. Never return a 404 for an expired job that received traffic. Instead, implement a soft-expiry workflow:

  1. Active Phase: Job is live, indexable, canonical points to self. Schema markup includes validThrough.
  2. Grace Period (7 days post-expiry): Page remains accessible with a "This position has been filled" banner. Add noindex meta tag. Keep the content visible for users who bookmarked it, but tell Google to drop it.
  3. Archive Phase: Redirect (301) the expired job URL to the most relevant category page (e.g., "Marketing Jobs in Kathmandu"). This preserves link equity from any external backlinks the specific job acquired.
  4. Sitemap Hygiene: Your XML sitemap must ONLY contain active jobs. Run a scheduled command hourly to regenerate the sitemap and remove expired entries. Submit sitemaps split by category to aid debugging in Search Console.
ACTIVE JOBIndex: YESSitemap: IncludedSchema: validThroughGRACE PERIODIndex: NOINDEXSitemap: RemovedUI: "Filled" BannerARCHIVEDHTTP: 301 RedirectTarget: Category PageLink Equity: PreservedExpires + 0dExpires + 7d
Technical SEO lifecycle for job postings: transitioning from indexable active state to noindex grace period, then 301 redirect to preserve link equity. This prevents crawl budget waste during building a Nepal job portal from scratch.

Additionally, implement JobPosting schema.org markup rigorously. Google for Jobs relies entirely on this structured data. Validate every listing against Google’s Rich Results Test before deployment. Missing datePosted or employmentType will exclude you from the job carousel, which drives the majority of organic traffic in this niche.

How do you handle CV uploads and file security in Laravel?

Resumes contain PII (Personally Identifiable Information). Storing them in the public web root is a critical security vulnerability. On legal-tech portals I’ve built, document security is non-negotiable, and the same standards apply to job applications. Never store CVs in public/uploads/. Use Laravel’s private filesystem driver and serve files through signed URLs or a controller that checks authorization.

For a job portal, employers should only access CVs for jobs they own. Implement policy-based authorization:

// In ApplicationController.php
public function downloadCv(Application $application)
{
    // Authorize: only the employer who owns the job can download
    if ($application->job->employer_id !== auth()->id()) {
        abort(403);
    }

    // Return file from private disk with secure headers
    return Storage::disk('private')->download(
        $application->cv_path,
        'candidate-cv-' . $application->id . '.pdf',
        ['Content-Type' => 'application/pdf']
    );
}

Validate file types strictly on the server side. MIME type checking alone is insufficient; attackers can spoof Content-Type headers. Use the mimes validation rule combined with file extension whitelisting (pdf,doc,docx). Scan uploads with ClamAV if possible, especially if you allow executable formats (which you shouldn’t). For performance, offload virus scanning to a queued job so the upload response remains instant.

What infrastructure supports high-frequency job searches and alerts?

Search is the core product. Default MySQL LIKE queries won’t scale beyond a few thousand listings. For a production Nepal job portal, you have two viable paths depending on budget and complexity tolerance.

FeatureMySQL Full-Text (InnoDB)Meilisearch / Typesense
Setup ComplexityLow (built-in)Medium (separate service)
Relevance RankingBasic TF-IDFTypo-tolerant, customizable
Nepali Language SupportPoor (needs custom tokenizer)Good (Unicode-native)
Faceted FilteringSlow on large datasetsInstant, native support
Infrastructure CostZero extra (uses DB server)~Rs 2,000–4,000/mo VPS
Best For<5,000 active jobs>5,000 jobs + typo tolerance

If you choose Meilisearch (my recommendation for serious portals), use Laravel Scout with Meilisearch for seamless Eloquent integration. Index only active jobs. Configure synonyms for Nepali/English variations: "ktm" → "kathmandu", "dev" → "developer". This dramatically improves zero-result rates.

LARAVEL APPJob Created/UpdatedScout Sync QueueSearch ControllerFilter BuilderMEILISEARCHIndex: jobsSynonyms: ktm→kathmanduFacets: district, salaryTypo Tolerance: ONUSER BROWSERSearch Query + FiltersInstant ResultsPaginationEmail Alert SignupSync DataJSON Response
Search architecture for a Nepal job portal: Laravel syncs job data to Meilisearch via queued jobs, enabling typo-tolerant, faceted search with instant responses for end users.

Email alerts are equally critical. Job seekers expect daily or weekly digests matching their criteria. Do not send emails synchronously during registration. Use Laravel Queues with Redis as the driver. Batch alert emails to respect SMTP rate limits. Personalize subject lines with actual job titles, not generic "New Jobs Available." Track open rates and unsubscribe links meticulously; spam complaints will destroy your domain reputation faster than any technical debt.

Start Building Your Nepal Job Portal with the Right Foundation

Building a Nepal Job Portal from Scratch is a significant engineering undertaking that demands attention to local payment realities, SEO hygiene, and scalable search architecture. Start with a solid Laravel 12 foundation, model your database around job lifecycles rather than static content, and integrate eSewa/Khalti with proper webhook verification from day one. Prioritize technical SEO early to avoid costly rewrites later. If you need guidance on architecture decisions, payment integration, or performance optimization for your job portal project, reach out to discuss your requirements. I help founders and agencies build production-grade platforms tailored to the Nepali market.

Frequently Asked Questions

Laravel 12 with PHP 8.4, MySQL 8.0, and Vue.js or Livewire provides the ideal balance of development speed, SEO control, and long-term maintainability for Nepali job portals requiring complex search and user roles.

Custom development typically ranges from NPR 300,000 to 800,000 (USD 2,250–6,000) depending on features like employer dashboards, payment integration, and automated matching algorithms.

Yes, for simple listings under 5,000 jobs using WP Job Manager, but Laravel is superior for high-volume portals needing custom application workflows, granular RBAC, and scalable search performance.

Use official REST APIs with server-side verification callbacks. In my experience building platforms like Ajako Deal, always validate transaction signatures on your backend before activating listings to prevent fraud and handle webhook retries gracefully.

Normalize data across employers, jobs, applications, and candidates tables with proper foreign keys. Index columns like location, category, salary_range, and posted_at for fast filtering, and use JSON columns only for flexible metadata that doesn't require relational queries.

Store all dates as UTC timestamps in MySQL and convert to BS only at the presentation layer using packages like nepali-date-converter. This prevents sorting and range-query issues while displaying culturally correct dates to Nepali users without corrupting your data integrity.

Implement JobPosting schema markup, canonical URLs for filtered views, XML sitemaps updated hourly, and fast Core Web Vitals. I've seen job boards fail because duplicate filter combinations created thousands of thin pages that diluted crawl budget and hurt rankings.

Use MySQL FULLTEXT indexes with ngram parser for Devanagari support, or deploy Meilisearch for better relevance ranking. Standard LIKE queries won't scale beyond 10,000 listings and will cause timeout errors during peak traffic periods.

Encrypt PII at rest, store files outside webroot with signed URLs, enforce strict RBAC using Spatie Laravel Permission, and comply with Nepal's Privacy Act 2075. Never log sensitive applicant data and sanitize all file uploads to prevent malicious script execution.

Use Spatie Laravel Permission with separate guards or role hierarchies. Employers need company verification, job management, and applicant viewing permissions, while candidates need profile editing, application tracking, and saved-job functionality without cross-access vulnerabilities.

Deployer 7 with symlinked releases on Ubuntu 24 LTS running PHP-FPM 8.4. Maintain shared storage for uploaded resumes and .env files, invalidate OPcache after symlink swap, and use GitLab CI pipelines to automate testing before production deployment.

Use Laravel queues with Redis to process notifications asynchronously and integrate with transactional services like AWS SES or Mailgun. Configure bounce handling, respect unsubscribe requests immediately, and throttle sends to avoid ISP blocks common with Nepali hosting providers.

Cache search results and filter facets in Redis with tag-based invalidation when jobs are created or updated. Use query result caching for popular categories and locations, but never cache authenticated user sessions or real-time application status data.

Build Artisan commands using Laravel Excel to parse CSV/XLSX files with validation, deduplication logic, and progress logging. Run migrations during off-peak hours with database transactions to ensure atomic imports and maintain referential integrity throughout the process.

Expect NPR 15,000–40,000 monthly (USD 110–300) covering server hosting, SSL renewal, framework updates, security patches, backup monitoring, and occasional feature adjustments based on employer feedback and changing payment gateway API requirements.

Share this article

Quick Contact Options
Choose how you want to connect me: