Hook — 05 : 38 a.m., Medellín ↔ Playa del Carmen pairing sprint
A humid dawn breeze rolled through my Colombian apartment when Andrés, coding from a beach café in Playa del Carmen, pinged me: “Our Options-API component looks like spaghetti; the new intern can’t follow the reactivity.” I watched his screen over shaky Wi-Fi: data, computed, watchers, and methods scattered like dominoes. We refactored the same logic with Vue 3’s Composition API—grouped by feature, powered by <script setup>, and fully typed—then hot-reloaded. The bundle size stayed lean, scroll jank vanished, and the intern dropped a celebratory 🌮 emoji. That cross-coast refactor frames today’s journey into two paradigms that power modern Vue.js apps.


Why This Choice Still Matters in 2025

Vue 3 ships both APIs to ease migration and honor developer preference, but picking one per codebase reduces cognitive load, speeds onboarding, and clarifies documentation. The Composition API unlocks stronger TypeScript inference, granular logic reuse, and tree-shakable bundle size, while the Options API shines for quick prototypes and teams comfortable with the classic mental model. Understanding their trade-offs lets you scale from solo projects in a Costa Rican surf shack to international teams shipping SaaS out of São Paulo.


The Heart of Each API

Options API — Declarative Cohesion

You describe what a component has: data, computed, methods, watch, props, and lifecycles. Vue sorts execution order and merges mixins under the hood.

vueCopyEdit<script>
export default {
  props: { price: Number },
  data() {
    return { quantity: 1 };
  },
  computed: {
    total() {
      return this.price * this.quantity;
    },
  },
  methods: {
    inc() { this.quantity++; }
  },
};
</script>

Composition API — Logic-First Clarity

You declare how the feature works. Reactive primitives (ref, reactive, computed, watch) combine freely inside setup() or a <script setup> block.

vueCopyEdit<script setup>
import { ref, computed } from 'vue';

const props = defineProps({ price: Number });

const quantity = ref(1);
const total = computed(() => props.price * quantity.value);
const inc = () => quantity.value++;
</script>

Grouping by feature—rather than by option—means state, derivatives, and side-effects live together even as components grow.


When to Reach for Composition


Where Options Still Shine


Hands-On Migration Walkthrough

Imagine an Options component that fetches products and filters them by search term.

Original Options Code

vueCopyEdit<script>
export default {
  data() {
    return { products: [], search: '' };
  },
  computed: {
    filtered() {
      return this.products.filter(p =>
        p.name.toLowerCase().includes(this.search.toLowerCase())
      );
    },
  },
  mounted() {
    fetch('/api/products')
      .then(r => r.json())
      .then(d => (this.products = d));
  },
};
</script>

Composition Rewrite

vueCopyEdit<script setup>
import { ref, computed, onMounted } from 'vue';

const products = ref([]);
const search   = ref('');

const filtered = computed(() =>
  products.value.filter(p =>
    p.name.toLowerCase().includes(search.value.toLowerCase())
  )
);

onMounted(async () => {
  products.value = await (await fetch('/api/products')).json();
});
</script>

Benefits Observed
Grouped concerns—fetch logic, state, derived data—in one chunk. Adding debounce, pagination, or error handling happens beside the fetch, not in remote lifecycle hooks.


Extracting a Reusable Composable

tsCopyEdit// composables/useProducts.ts
import { ref, computed, onMounted } from 'vue';

export function useProducts() {
  const list = ref<Product[]>([]);
  const search = ref('');

  const filtered = computed(() =>
    list.value.filter(p =>
      p.name.toLowerCase().includes(search.value.toLowerCase())
    )
  );

  onMounted(async () => {
    list.value = await (await fetch('/api/products')).json();
  });

  return { list, search, filtered };
}

Consume it anywhere:

vueCopyEdit<script setup>
import { useProducts } from '@/composables/useProducts';

const { filtered, search } = useProducts();
</script>

Options API could achieve similar reuse via mixins, but composables avoid name collisions, support generics, and tree-shake when not imported.


Remote-Work Insight Box

Two months back in Panamá, our design team hot-swapped product-card styles. With Options, remapping prop names across twenty components took three PRs. Using Composition, we wrapped useCardStyle() to supply classes and sizes; design switched palettes via one function, merged once, and islands of code remained untouched—velocity wins that matter when team members review after dinner in Mexico.


Pitfalls to Dodge

ScenarioSneaky IssueQuick Fix
Mixing APIs in one fileConfusing this scopeStick to one API per component
Reactive object lostAssigning new value to reactive proxyUse Object.assign or ref for primitives
Circular imports in composablesHidden state couplingExtract base util or rely on injection
Over-composingTen tiny composables per featureMerge related logic to keep call sites readable

CLI Shortcuts and Ecosystem Helpers

CLI / LibWhat it does
npm init vue@latestScaffolds Vue 3 project with Composition API + TS
vue add vue-i18ni18n plugin integrates with both APIs
vite-plugin-inspectVisualize reactivity graph for composables
eslint-plugin-vueRules to forbid mixing Options & Composition

Performance & Accessibility Checkpoints


Diagram Idea (textual)

Tree comparing a 300-line Options component sliced across five option blocks versus a Composition refactor with grouped feature islands—highlighting flow of ref and computed nodes.


Wrap-Up

Composition and Options aren’t rivals—they’re siblings. Options remains a gentle on-ramp, while Composition unlocks scale, reuse, and type safety. Pick one intentionally, document team conventions, and stick with it. Your future self—and that intern picking up code on a shaky hostel Wi-Fi in Costa Rica—will thank you.

Got a Vue-API tale or question? Drop it below; I’ll reply between layovers and late-night arepa sessions.

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x