Tech Stack 2025
2025-01-03
web-development
javascript
react
The React ecosystem is a dynamic landscape of constantly evolving technologies. This article delves into a powerful technology stack for building full-stack applications in 2025, allowing you to bring your own product (such as a SaaS) or its Minimum Viable Product (MVP) to life.As an experienced Fullstack web developer, I've spent years honing my approach. Annual re-evaluations of the technology stack are crucial to balancing cutting-edge trends with long-term project stability and maintainability.My latest work experience, which culminated in November 2024, has provided me with valuable feedback. While I am satisfied with the initial technology stack, hindsight offers valuable lessons for future projects.Let's embark on this journey of discovery and explore the exciting possibilities that await in this concise yet powerful selection.React as a full-stack frameworkRemix.jsRemix.js is a full-stack web framework that prioritizes developer experience and leverages web fundamentals to create fast, resilient, and user-friendly web applications.Key Features:Data Loading and Fetching: Remix simplifies data fetching with built-in loaders and actions. Loaders fetch data before rendering a route, while actions handle form submissions and other side effects.File-System Routing: Routes are defined as files within your project's file system, making the routing structure intuitive and easy to understand.Server-Side Rendering (SSR): Remix excels at SSR, providing excellent SEO and faster initial page loads.Data Streaming: Remix can stream data to the client, improving perceived performance and user experience.Form Handling: Built-in form handling simplifies common tasks like validation, submission, and error handling.Testing: Remix encourages testing at various levels, including unit tests, integration tests, and end-to-end tests.Flexibility: Remix can be deployed to various environments, including Node.js servers and edge computing platforms like Cloudflare Workers.Benefits of Using Remix:Improved Performance: SSR and data streaming contribute to faster page loads and a smoother user experience.Enhanced Developer Experience: Remix's focus on developer experience makes it enjoyable to work with, thanks to its intuitive routing, data fetching mechanisms, and built-in features.Flexibility and Scalability: Remix can be deployed to various environments, making it adaptable to different project needs.Strong Community and Ecosystem: Remix has a growing community and a supportive ecosystem with various resources and tools available.In essence, Remix.js offers a modern and efficient approach to web development, empowering developers to build high-quality, performant, and user-centric applications.AstroConsidering a dedicated landing page? Astro shines for this task!While Remix.js excels at monolithic applications serving both static and dynamic content, Astro offers a compelling alternative specifically for crafting exceptional landing pages. Here's why Astro might be the perfect fit:Key Features:Lightning-Fast Performance: Astro prioritizes speed, delivering blazing-fast landing pages that keep visitors engaged.Intuitive File-Based Routing: Similar to Remix, Astro leverages a file-based routing system, making it easy to structure and manage your landing page content.Component-Based Development: Build reusable components for a streamlined development process and consistent design across your landing page.Integration with Multiple Frameworks: Astro seamlessly integrates with popular frameworks like React, Vue, and Svelte, empowering you to leverage your existing skills and preferences.Headless Content Management System (CMS) Support: Astro plays nicely with various headless CMS solutions, allowing for flexible content management of your landing page.Benefits of Using Astro for Landing Pages:Focus on Developer Experience: Astro's clean syntax and file-based structure streamline development, freeing you to concentrate on crafting an impactful landing page.Rapid Prototyping: Astro's speed makes it ideal for rapid prototyping and iterating on your landing page design.SEO Optimization: Astro generates clean, well-structured HTML, contributing to strong Search Engine Optimization (SEO) for your landing page.Reduced Build Times: Astro's incremental builds minimize build times, allowing for faster development cycles.By leveraging Astro's strengths, you can create a high-performing, developer-friendly landing page that captures leads and fuels your SaaS growth, all while saving valuable time to focus on core product development within your Remix/Next application.Server ComponentsImagine you're building a house. Server Components are like the construction workers handling the heavy lifting and specialized tasks. Instead of doing everything inside your house (the browser), these components work outside, on the server.What do they do?Fetch materials: They retrieve data from a database or API, like going to get bricks to build a wall.Do complex calculations: They perform complicated math or logic operations, like calculating the area of a room.Protect your house: They handle security tasks, like checking if someone is allowed to enter.Why are they useful?Your house is built faster: By doing part of the work on the server, your website loads faster for visitors.Your house is more secure: Sensitive data is handled in a safer place, out of reach of intruders.You can focus on the decoration: Server components handle the heavy lifting, so you can focus on making your website look nice and work well.Server FunctionsThink of your house having an intercom system. Server Functions are like using that intercom to ask a worker outside the house to do something.How do they work?You (your React component) tell the worker (the server function) what to do, like "please bring more bricks".The worker does the task and gives you the result.Why are they useful?It's very easy to communicate: You don't have to worry about the technical details of sending and receiving messages.You can do many things: You can ask the server function to do almost anything that a server component can do.Server ActionsImagine you have a list of pre-defined commands for your intercom. Server Actions are like those commands.What are they?They are server functions that are designed to perform specific tasks, like submitting a form or updating a database.Why are they useful?They are easy to use: They are already set up to do something specific, so you don't have to write a lot of code.There are many libraries that help you: There are libraries like next-safe-actions and zsa that provide you with pre-defined server actions for common tasks.State Management in ReactZustandZustand is a lightweight and flexible state management library for React applications. It offers a simple and intuitive API for managing global and local state, making it an excellent choice for projects of all sizes.Key Features:Minimalistic API: Zustand boasts a concise and easy-to-learn API with minimal boilerplate code.Performance-Oriented: Zustand is designed for optimal performance, with efficient state updates and minimal overhead.Flexible: It offers a flexible and modular approach to state management, allowing you to create and manage multiple stores as needed.Easy to Learn: The simple API and clear documentation make Zustand easy to learn and integrate into your React projects.import create from "zustand";
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));
function Counter() {
const count = useStore((state) => state.count);
const increment = useStore((state) => state.increment);
return <button onClick={increment}>Count: {count}</button>;
}RecoilRecoil.js is a state management library for React applications that provides a more granular and flexible approach to managing shared state compared to traditional methods like Context API. It offers a unique data flow graph that allows you to create complex state structures and derive new state from existing ones.Key Concepts:Atoms: These are the fundamental units of state in Recoil. Atoms are independent and can be subscribed to by multiple components. They provide a way to store and share simple values.Selectors: Selectors are pure functions that derive new state from existing atoms or other selectors. They allow you to create complex state structures and perform computations on the fly.RecoilRoot: This component is the root of your Recoil application. It provides the context for all Recoil atoms and selectors.Subscriptions: Components subscribe to atoms or selectors to receive updates when the state changes. Recoil uses efficient mechanisms to ensure that components only re-render when the data they depend on has actually changed.Advanced Features:Asynchronous Values: Recoil supports asynchronous values, allowing you to fetch data from APIs and manage loading states.Persistence: You can persist Recoil state to local storage or other storage mechanisms to restore it on subsequent page loads.Time Travel Debugging: Recoil provides tools for time travel debugging, allowing you to inspect and rewind state changes.Custom Hooks: You can create custom hooks to encapsulate complex state management logic.import { atom, selector, useRecoilState, useRecoilValue } from "recoil";
// Atom for user data (fetched asynchronously)
const userDataAtom = atom({
key: "userData",
default: null,
effects_UNSTABLE: [
({ setSelf }) => {
// Fetch user data from API and set it
},
],
});
// Selector to extract the user's name
const userNameSelector = selector({
key: "userName",
get: ({ get }) => {
const userData = get(userDataAtom);
return userData?.name || "Guest";
},
});
function UserProfile() {
const userName = useRecoilValue(userNameSelector);
return <div>Hello, {userName}!</div>;
}CSS Styling in ReactTailwind CSSGame-Changer for Rapid DevelopmentWhile opinions on Tailwind CSS vary within the developer community, I strongly believe it's currently the most effective solution for rapid product development and long-term CSS maintainability.Based on my own experience and the feedback of many co-workers, Tailwind offers several key advantages:Rapid Prototyping Tailwind's utility-first approach empowers developers to quickly build and style UI elements without writing custom CSS classes. This significantly accelerates the prototyping and iteration process.Consistent Styling Tailwind provides a pre-defined set of utility classes, ensuring consistent styling across your entire project. This eliminates the need to constantly reinvent the wheel and helps maintain a cohesive design system.Improved Developer Experience Tailwind's intuitive syntax and autocompletion features in modern code editors enhance the developer experience, making it faster and more enjoyable to write and maintain CSS.Reduced CSS File Size By leveraging pre-defined utility classes, you can often significantly reduce the overall size of your CSS files, leading to faster page load times and improved performance.Strong Community and Ecosystem Tailwind boasts a large and active community, providing access to extensive documentation, helpful resources, and a wealth of community-built plugins and extensions.In my experience, the initial learning curve for Tailwind is relatively minor. Most developers become proficient within a week, and the long-term benefits in terms of development speed and maintainability far outweigh the initial investment.I encourage you to give Tailwind a try. You might just be surprised at how much it can streamline your CSS workflow and boost your productivity.Data Fetching in ReactReact/Tanstack QueryFor most data fetching needs, I prioritize Server Components due to their inherent performance advantages and improved data security. By handling data loading on the server, I can minimize the amount of JavaScript executed in the browser, resulting in faster initial page loads and a better user experience.However, for more complex scenarios such as infinite scrolling, pagination, or real-time data updates, I leverage the power of React Query. React Query provides a robust and flexible solution for managing data fetching, caching, and updates on the client-side.Example:Server Components: Ideal for fetching initial data for a product page, user profile, or blog post.React Query: Excellent for implementing infinite scrolling on a feed, managing paginated data in a table, or handling real-time updates for a chat application.By strategically combining Server Components and React Query, I can achieve an optimal balance between performance, maintainability, and developer experience in my React applications.Database & ORMPrismaMy Preferred Choice for Database InteractionsPrisma ORM remains my preferred choice for interacting with databases in my React projects. While newer ORMs like Drizzle are gaining traction, Prisma has proven to be a stable and reliable solution with a strong community and extensive documentation.Key Features of Prisma:Type Safety: Prisma generates TypeScript types from your database schema, ensuring type safety throughout your application and reducing the risk of runtime errors.Example:const user = await prisma.user.findUnique({
where: { id: 1 },
include: { posts: true },
});The generated types for user and posts provide clear guidance and prevent unexpected data structures.Declarative Schema Definition: Define your database schema using Prisma Schema Language, a declarative and intuitive syntax.Example:model User {
id Int @id @default(autoincrement())
name String
email String @unique
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String
author User @relation(fields: [authorId], references: [id])
authorId Int
}Simplified Querying: Prisma provides a fluent and intuitive query builder API, making it easy to write complex database queries with minimal effort.Migrations: Prisma Migrate simplifies database schema changes with an easy-to-use migration system, allowing you to safely evolve your database over time.Benefits of Using PrismaIncreased Productivity: Prisma significantly improves developer productivity by automating repetitive tasks, such as generating SQL queries and managing database schema changes.Improved Code Quality: Type safety, generated types, and a focus on best practices contribute to higher code quality and fewer bugs.Enhanced Maintainability: Prisma's declarative approach and clear schema definitions make it easier to understand and maintain your database interactions over time.Strong Community and Ecosystem: Prisma has a large and active community, providing access to extensive documentation, tutorials, and support resources.While newer ORMs like Drizzle offer promising features, Prisma's stability, mature ecosystem, and strong focus on developer experience make it my go-to choice for most projects.SupabaseSupabase is an open-source Firebase alternative that offers a comprehensive suite of backend services, including a real-time PostgreSQL database, authentication, storage, and edge functions. It provides developers with a rapid and efficient way to build full-stack web applications without the hassle of managing infrastructure.Key Features of Supabase:Real-time PostgreSQL: Supabase leverages PostgreSQL for its robust database capabilities, allowing you to create complex data models and perform powerful queries. The real-time features enable you to build applications with live updates, such as chat apps and dashboards.Authentication: Supabase provides a flexible authentication system that supports various methods like email/password, social logins, and custom authentication providers. It also offers features like passwordless authentication and multi-factor authentication.Storage: Supabase includes a file storage service that allows you to upload and manage files directly from your application. You can generate public URLs for files and set permissions to control access.Edge Functions: These serverless functions allow you to execute custom code on the edge, closer to your users. This is useful for tasks like data transformation, server-side rendering, and custom authentication logic.GraphQL API: In addition to the REST API, Supabase also offers a GraphQL API, providing a more flexible and expressive way to query your data.Why Choose Supabase?Rapid Development: Supabase accelerates development by providing pre-built backend services, allowing you to focus on building your application's frontend.Scalability: Supabase is built on scalable infrastructure, making it suitable for applications of all sizes.Open Source: Being open-source, Supabase offers transparency, flexibility, and a strong community.Cost-Effective: Supabase offers a generous free tier and flexible pricing plans, making it affordable for both small and large projects.When to Use SupabaseReal-time Applications: Supabase is ideal for applications that require real-time updates, such as chat apps, collaborative tools, and dashboards.Rapid Prototyping: Supabase's ease of use makes it an excellent choice for quickly building prototypes and MVPs.Full-stack Web Applications: Supabase can be used as the backend for both simple and complex web applications.Data Handling & ValidationTypeScriptTypeScript is undeniably the industry standard for JavaScript projects. Its static type system, combined with modern features like interfaces and modules, offers a range of benefits, including stronger type safety, improved error detection, increased productivity, and a more enjoyable development experience. The industry's adoption of TypeScript is a testament to its value and effectiveness.ZodA Powerful Tool for Type-Safe ValidationZod has emerged as a leading choice for validation in React projects, particularly when combined with TypeScript. By leveraging Zod's type-safe approach, you can significantly enhance the robustness and maintainability of your applications.Key Features of ZodType-Safe Validation: Zod leverages TypeScript's type system to define and enforce data schemas. This ensures that the data received by your application conforms to the expected structure, preventing unexpected errors and improving data integrity.Declarative Schemas: Zod allows you to define data schemas declaratively using a concise and expressive syntax. This makes it easy to create complex validation rules for your data.Error Handling: Zod provides detailed and informative error messages, making it easier to identify and fix validation issues. These error messages can be easily integrated into your user interface to provide helpful feedback to users.Extensibility: Zod offers a flexible and extensible API, allowing you to create custom validation rules and integrate with other parts of your application.Benefits of Using ZodImproved Code Quality: By enforcing data types and validation rules, Zod helps you write more robust and reliable code with fewer unexpected errors.Enhanced Developer Experience: Zod's type-safe approach and informative error messages significantly improve the developer experience by making it easier to write, debug, and maintain your code.Improved User Experience: By providing clear and helpful error messages to users, Zod helps to improve the overall user experience of your application.Reduced Maintenance Costs: By catching data validation issues early on, Zod can help to reduce the long-term maintenance costs associated with your application.My ApproachWhile Zod offers powerful client-side validation capabilities, I prefer to primarily use it for server-side validation, particularly within Server Actions. This approach keeps client-side forms lightweight and avoids the complexity introduced by many third-party form libraries. By relying on native HTML validation for basic checks, I can maintain a lean and efficient form component architecture.Testing & ToolingMock Service Worker (MSW)One tool that has dramatically improved my workflow is Mock Service Worker (MSW). If youâre not using it yet, let me show you why itâs worth your attention.Mock Service Worker is a powerful JavaScript library for API mocking. It intercepts requests on the network level using Service Workers, allowing you to mock APIs directly in the browser or Node.js runtime. This makes it perfect for testing, debugging, and even development without relying on a backend.Why I Love Using MSWFor me, MSW solves so many problems that other mocking libraries canât:Realistic Mocking: MSW intercepts requests at the network level, so the mocked behavior is almost indistinguishable from a real server. Itâs like having a backend emulator in your pocket.Client and Server Testing: Whether youâre testing a React app or a Node.js service, MSW works seamlessly in both environments.Reduced Dependencies: No need for extra test servers or complex mocking setups. MSW keeps it clean and simple.Flexibility: You can mock REST, GraphQL, and even WebSocket APIs. If your app can make the request, MSW can mock it.Better Debugging: With clear logs and debugging tools, you know exactly which requests are being mocked and how.MSW vs. Traditional Mocking ToolsIn my experience, MSW stands out from tools like Axios interceptors or custom mocks:Scalability: With MSW, your mocks live outside your application logic, making them reusable and maintainable.Isolation: Unlike interceptors, MSW doesnât interfere with your applicationâs code. This means no messy teardown code after tests.Browser-Like Behavior: By using Service Workers, MSW mimics browser-level behavior, ensuring your tests are as close to real-world conditions as possible.Why You Should Try MSWAPIs are the backbone of modern apps, and testing them doesnât have to be painful. MSW provides a realistic, flexible, and developer-friendly way to mock APIs without unnecessary complexity.Whether youâre developing, debugging, or testing, MSW is a game-changer. Itâs the tool I didnât know I needed but now canât live without.If youâre looking to elevate your development process in 2025, give MSW a try. Your team will thank you, and your code will shine.PlaywrightWhen it comes to modern web testing in 2025, Playwright has become one of my go-to tools. Itâs not just a testing library; it feels like a power tool for front-end developers who want precision, speed, and versatility.Playwright is a Node.js library for browser automation. Built by Microsoft, it allows you to write end-to-end tests for web applications across all major browsers (Chromium, Firefox, WebKit) with one consistent API. Itâs like having a Swiss Army knife for browser testing thatâs sleek, powerful, and developer-friendly.Why Playwright Stands OutFrom my experience, Playwright excels in:Multi-Browser Support: Unlike Cypress, which only supports Chromium-based browsers out of the box, Playwright lets you test Chromium, Firefox, and WebKit. This makes it indispensable for ensuring your app works across different environments.Parallel Testing: Playwrightâs built-in parallelization is a game-changer. Tests run faster, which keeps the CI pipeline smooth and developers productive.Headless and Headed Modes: Whether youâre debugging or running tests in CI, Playwright adapts seamlessly.Context Isolation: With Playwright, you can create isolated browser contexts that mimic different users. This is a lifesaver for apps with complex authentication flows or multi-tenant scenarios.API Testing: Playwright doesnât stop at UI. You can make API calls directly within your test scripts, ensuring your front-end and back-end work harmoniously.Letâs See Some CodeHereâs a quick example of writing a Playwright test in TypeScript. This test checks a login page:import { test, expect } from "@playwright/test";
test.describe("Login Page Tests", () => {
test("should log in successfully with valid credentials", async ({
page,
}) => {
await page.goto("https://example.com/login");
// Fill out the login form
await page.fill("#username", "testuser");
await page.fill("#password", "securepassword");
await page.click('button[type="submit"]');
// Assert redirection to the dashboard
await expect(page).toHaveURL("https://example.com/dashboard");
await expect(page.locator("h1")).toHaveText("Welcome, testuser!");
});
test("should show an error for invalid credentials", async ({ page }) => {
await page.goto("https://example.com/login");
// Fill out the form with invalid data
await page.fill("#username", "wronguser");
await page.fill("#password", "wrongpassword");
await page.click('button[type="submit"]');
// Assert error message is displayed
await expect(page.locator(".error-message")).toHaveText(
"Invalid credentials"
);
});
});Testing is no longer optional in 2025. Users expect flawless experiences, and automation is how we deliver. Playwright combines power with developer-friendly features, making it a must-learn tool.If you havenât explored it yet, now is the time. Your future self will thank you when your tests run faster, your bugs decrease, and your users stay happy.Deployment & HostingCloudflare (Domain & CDN)Cloudflare remains a cornerstone of modern web development. For me, itâs not just a serviceâitâs an integral part of building fast, secure, and scalable applications. Whether youâre an indie developer or part of a massive team, Cloudflare has tools that will elevate your stack.What is Cloudflare?Cloudflare is a comprehensive suite of web performance and security tools. It started as a Content Delivery Network (CDN), but today, itâs much more. With Cloudflare, you can optimize your websiteâs performance, protect it from malicious attacks, and even build serverless applications using their powerful edge computing platform.Why I Rely on CloudflareHere are the standout reasons why Cloudflare is an essential part of my stack:Speed Everywhere: With its global CDN, Cloudflare ensures that your appâs static assets are delivered lightning-fast, no matter where your users are. Their caching is a lifesaver for apps with heavy assets or global audiences.Unmatched Security: Cloudflareâs Web Application Firewall (WAF) and DDoS protection have saved me countless headaches. Itâs like having a security team on autopilot.Serverless Edge Computing: Using Cloudflare Workers has been a game-changer. It allows me to run lightweight functions at the edge, reducing latency and offloading work from traditional servers.Ease of Use: Setting up Cloudflare takes minutes, but the benefits are immense. Their intuitive dashboard and developer-friendly tools make it easy to integrate with any stack.Cost-Effective: For the value it provides, Cloudflareâs pricing is unbeatable. Even their free tier is packed with features that can get you started without worrying about costs.Building modern apps means delivering fast, secure, and reliable experiences. Cloudflare empowers you to achieve all of this without overcomplicating your stack. From their unbeatable CDN to their innovative edge computing platform, itâs a tool Iâd recommend to any developer looking to future-proof their applications in 2025.If you havenât explored Cloudflare yet, now is the perfect time. Your users will feel the difference, and so will you.Other Utilities:React Email and ResendA Powerful Combination for Email DeliveryReact Email and Resend offer a compelling solution for crafting and delivering high-quality emails within your React applications.React Email: This library empowers you to build visually appealing and responsive email templates directly within your React components. By leveraging familiar React concepts like components, state, and props, you can create dynamic and maintainable email designs.Resend: This robust email API provides a reliable and efficient way to send transactional emails, such as welcome emails, password resets, and order confirmations. Resend offers features like high deliverability, robust analytics, and easy integration with your existing infrastructure.Key Benefits:Improved Developer Experience: React Email enhances the developer experience by allowing you to build email templates using familiar React patterns, leading to increased productivity and maintainability.Consistent Branding: By using React components for your email templates, you can ensure consistent branding and styling across your entire application, including emails.Enhanced Deliverability: Resend's robust infrastructure and focus on deliverability help ensure your emails reach the intended recipients reliably.Easy Integration: Resend offers a straightforward API and SDKs for easy integration with your React application.Example:// src/components/EmailTemplates/WelcomeEmail.jsx
import * as React from "react";
import { Html, Head, Title, Body, P, H1 } from "@react-email/components";
export const WelcomeEmail = ({ name }) => (
<Html>
<Head>
<Title>Welcome to Our App!</Title>
</Head>
<Body>
<H1>Hello, {name}!</H1>
<P>Welcome to our app! We're excited to have you join us.</P>
{/* ... more email content ... */}
</Body>
</Html>
);// src/pages/api/sendWelcomeEmail.js
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_API_KEY);
export default async function handler(req, res) {
try {
await resend.emails.send({
from: "no-reply@yourdomain.com",
to: "recipient@example.com",
subject: "Welcome to Our App!",
html: await renderToString(<WelcomeEmail name="John Doe" />),
});
res.status(200).json({ success: true });
} catch (error) {
console.error(error);
res.status(500).json({ error: "Failed to send email" });
}
}This example demonstrates how to use React Email to create a simple welcome email template and then use the Resend API to send it.By combining the power of React Email and Resend, you can streamline your email workflows, improve the quality of your email communications, and enhance the overall user experience.StripeStripe is a widely-used and robust payment gateway that offers a comprehensive suite of features for accepting online payments.Potential ChallengesComplexity: While powerful, Stripe's extensive feature set can sometimes feel overwhelming, especially for smaller projects or those with simpler payment requirements.Evolving API: Stripe continuously introduces new features and updates its API, which can occasionally require adjustments to your integration.import React, { useState } from "react";
import { loadStripe } from "@stripe/stripe-js";
const stripePromise = loadStripe("YOUR_STRIPE_PUBLIC_KEY");
function CheckoutForm() {
const [loading, setLoading] = useState(false);
const handleSubmit = async (event) => {
event.preventDefault();
setLoading(true);
try {
const stripe = await stripePromise;
const { error } = await stripe.redirectToCheckout({
lineItems: [
{
price: "price_1234567890abc123",
quantity: 1,
},
],
});
if (error) {
console.error(error);
// Handle error (e.g., display an error message to the user)
}
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
{/* ... form fields ... */}
<button type="submit" disabled={loading}>
{loading ? "Processing..." : "Pay Now"}
</button>
</form>
);
}
export default CheckoutForm;Essentially, this is the tech stack that I would choose today for a new full-stack React project. This is just one possible combination, and the best tech stack for your project will ultimately depend on your specific requirements and priorities. I encourage you to explore these technologies and experiment with different combinations to find what works best for you.I hope this has been helpful and/or taught you something new!Profile@khriztianmoreno ïżœ