Setup & config

Install one module, then shape it from two files: nuxt.config.ts for build-time, app.config.ts for everything the kit reads at runtime.

Source in the kit: module.ts · core.config.ts · locale/ · theme/

Starter template

Starting from scratch? Skip steps 1–2

A Nuxt 3 project with @finema/core already installed and configured. Clone it and start building instead of setting everything up by hand.

$git clone https://gitlab.finema.co/finema/shared/nuxt3-template-with-uikit.git my-app
Open the template on GitLab

1. Install

The module installs and configures @nuxt/ui, @pinia/nuxt and vee-validate for you.

bun add @finema/core

2. nuxt.config.ts

Add the module. Components, composables, helpers, v (valibot) and the vee-validate functions are then auto-imported everywhere.

export default defineNuxtConfig({
  modules: ['@finema/core'],

  // Where your API lives: read with useRuntimeConfig().public, overridable with NUXT_PUBLIC_* at runtime
  runtimeConfig: {
    public: {
      baseAPI: 'https://api.example.com',
    },
  },

  // Auto-import your loaders like the kit's own composables
  imports: {
    dirs: ['loaders'],
  },
})

3. app.config.ts

Everything under core is optional; these are the defaults. Date formats use date-fns tokens.

export default defineAppConfig({
  core: {
    site_name: '',                  // suffix of every page title
    color: '#3675FB',               // page loading bar
    locale: 'th',                   // 'th' or 'en': kit texts, datepicker language
    time_zone: 'Asia/Bangkok',      // TimeHelper and date columns display in this zone

    // What people see
    date_format: 'dd-MMM-yyyy',
    date_time_format: 'dd-MMM-yyyy HH:mm:ss',
    month_format: 'MMM-yyyy',
    time_format: 'HH:mm',
    is_thai_year: false,            // 2024 -> 2567
    is_thai_month: false,           // Feb -> ก.พ.

    // What the API receives
    date_format_system: 'yyyy-MM-dd',
    date_time_format_system: 'yyyy-MM-dd HH:mm:ss',

    // Loaders and tables
    limit_per_page: 25,
    default_primary_key: 'id',
  },
})

4. Changing the built-in texts

Dialog buttons, empty states, pagination and upload messages come from one dictionary. Override single entries; the rest keep the default for the locale. Keys are listed in src/runtime/locale/th.ts.

export default defineAppConfig({
  core: {
    messages: {
      common: {
        confirm: 'ยืนยัน',
        empty: 'ยังไม่มีรายการ',
      },
      upload: {
        maxSize: 'ไฟล์ใหญ่เกินไป (สูงสุด {size})',   // {placeholders} are filled in by the kit
      },
    },
  },
})

5. Theming

The kit maps the Nuxt UI semantic colours to its own palettes (primary → main, defined in src/runtime/styles/main.css). Re-colour a palette in CSS, or point a semantic colour at another palette. Component classes are tailwind-variants slots under ui; kit components (table, form, dialog, uploadFileDropzone…) are themed the same way as Nuxt UI ones.

// assets/css/main.css changes the brand palette itself:
//   @theme { --color-main-500: #7C3AED; --color-main-600: #6D28D9; /* …50 to 950 */ }

export default defineAppConfig({
  ui: {
    // or point a semantic colour at any Tailwind palette
    colors: {
      primary: 'violet',
    },
    // A Nuxt UI component
    button: {
      defaultVariants: {
        size: 'lg',
      },
    },
    // A kit component: slot names are in src/runtime/theme/table.ts
    table: {
      slots: {
        th: 'bg-slate-50 text-slate-600',
      },
    },
  },
})

Reading the config in code

examples/config/Current.vue

The live state below is this playground's merged config.

Today in this app: 06 พ.ย. 2569

Confirm button text: ตกลง

Upload size error: ขนาดไฟล์ต้องไม่เกิน 5 MB

<template>
  <div class="space-y-2 text-sm">
    <p>
      Today in this app:
      <strong>{{ TimeHelper.displayDate(new Date()) }}</strong>
    </p>
    <p>
      Confirm button text:
      <strong>{{ messages.common.confirm }}</strong>
    </p>
    <p>
      Upload size error:
      <strong>{{ format(messages.upload.maxSize, { size: '5 MB' }) }}</strong>
    </p>
  </div>
</template>

<script lang="ts" setup>
// useCoreConfig() is the merged result of the kit defaults and the `core` key of your app.config.ts
const config = useCoreConfig()

// Every text the kit renders by itself, in core.locale, with core.messages overrides applied
const { messages, format } = useCoreMessages()

defineExpose({
  debug: computed(() => config),
})
</script>