Amortization Calculator

Free Loan Repayment Schedule Tool

Amortization Calculator

$
%
Extra Payments
$
$
$

Loan Amortization Summary

Based on your inputted interest rate of 5.27%

How payments change over the life of a 30-year loan: As the term of your loan progresses, a larger share of your payment goes toward paying down the principal until the loan is paid in full at the end of your term.

Number of Payments: 360
Monthly Payment
$1,830.66
Total Interest Paid
$329,036.09
Total Cost of Loan
$659,036.09
Payoff Date
May 2055

Loan Balance Over Time

Loan Balance: $0.00
Principal Paid: $330,000.00
Interest Paid: $329,036.09

Amortization Schedule Breakdown

This table shows principal and interest for each payment.

First payment: July 2025 | Last payment: May 2055
| |
`); printWindow.document.close(); printWindow.print(); });exportCsvBtn.addEventListener('click', () => { const rows = [["Year", "Month", "Principal", "Interest", "Remaining Balance"]]; amortizationTableBody.querySelectorAll('details').forEach(detail => { const year = detail.querySelector('summary .summary-year').textContent; detail.querySelectorAll('.monthly-table tbody tr').forEach(row => { const cells = Array.from(row.querySelectorAll('td')).map(td => { const text = td.textContent.replace(/[^0-9A-Za-z\s.]/g, ''); return `"${text.replace(/"/g, '""')}"`; }); rows.push([year, ...cells]); }); }); const csvContent = "data:text/csv;charset=utf-8," + rows.map(e => e.join(",")).join("\n"); const link = document.createElement("a"); link.setAttribute("href", encodeURI(csvContent)); link.setAttribute("download", "amortization_schedule.csv"); document.body.appendChild(link); link.click(); document.body.removeChild(link); });// --- CORE LOGIC --- function getFormValues() { const loanAmount = parseCurrency(loanAmountInput.value); const loanTerm = parseInt(loanTermSelect.value, 10); const annualRate = parseFloat(interestRateInput.value) || 0; const startDate = startDateInput.value ? new Date(startDateInput.value) : new Date(); const oneTimeDate = oneTimeDateInput.value ? new Date(oneTimeDateInput.value) : new Date(); return { loanAmount, loanTerm, annualRate, startDate, extraMonthly: parseCurrency(extraMonthlyInput.value), extraYearly: parseCurrency(extraYearlyInput.value), oneTimeAmount: parseCurrency(oneTimeAmountInput.value), oneTimeDate }; }function calculateAndDisplay() { loadingSpinner.classList.add('active'); setTimeout(() => { const form = getFormValues(); const monthlyRate = form.annualRate / 1200; const maxPayments = form.loanTerm * 12;let monthlyPayment = 0; if (form.loanAmount > 0 && maxPayments > 0) { if (monthlyRate > 0) { monthlyPayment = form.loanAmount * (monthlyRate * Math.pow(1 + monthlyRate, maxPayments)) / (Math.pow(1 + monthlyRate, maxPayments) - 1); } else { monthlyPayment = form.loanAmount / maxPayments; } } monthlyPayment = Number(monthlyPayment.toFixed(2));const amortizationData = generateAmortization( form.loanAmount, monthlyRate, monthlyPayment, maxPayments, form.extraMonthly, form.extraYearly, form.oneTimeAmount, form.oneTimeDate, form.startDate ); updateUI(form, monthlyPayment, amortizationData); loadingSpinner.classList.remove('active'); }, 50); }function generateAmortization(principal, monthlyRate, monthlyPayment, maxPayments, extraMonthly, extraYearly, oneTimeAmount, oneTimeDate, startDate) { if (principal <= 0 || maxPayments <= 0) { return { yearlyData: {}, monthlyData: [], totalInterest: 0, numPayments: 0, firstPaymentDate: new Date(), lastPaymentDate: new Date() }; }let balance = principal; let totalInterest = 0; const firstPaymentDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1); let currentDate = new Date(firstPaymentDate); let lastPaymentDate = currentDate; const monthlyData = []; const yearlyData = {}; let oneTimeApplied = false; let paymentCount = 0;while (balance > 0.01 && paymentCount < maxPayments) { const year = currentDate.getFullYear(); const isYearStart = currentDate.getMonth() === 0;const interestPayment = balance * monthlyRate; let principalPayment = monthlyPayment - interestPayment + extraMonthly;if (isYearStart && extraYearly > 0 && currentDate > firstPaymentDate) { principalPayment += extraYearly; }if (!oneTimeApplied && oneTimeAmount > 0 && currentDate >= oneTimeDate) { principalPayment += oneTimeAmount; oneTimeApplied = true; }if (principalPayment > balance) { principalPayment = balance; }balance -= principalPayment; totalInterest += interestPayment; lastPaymentDate = new Date(currentDate); paymentCount++;monthlyData.push({ date: new Date(currentDate), interest: Number(interestPayment.toFixed(2)), principal: Number(principalPayment.toFixed(2)), balance: Number(Math.max(balance, 0).toFixed(2)) });if (!yearlyData[year]) { yearlyData[year] = { months: [], totalPrincipal: 0, totalInterest: 0, endBalance: 0 }; } yearlyData[year].months.push(monthlyData[monthlyData.length - 1]); yearlyData[year].totalPrincipal += principalPayment; yearlyData[year].totalInterest += interestPayment; yearlyData[year].endBalance = Math.max(balance, 0);currentDate.setMonth(currentDate.getMonth() + 1); }Object.keys(yearlyData).forEach(year => { yearlyData[year].totalPrincipal = Number(yearlyData[year].totalPrincipal.toFixed(2)); yearlyData[year].totalInterest = Number(yearlyData[year].totalInterest.toFixed(2)); yearlyData[year].endBalance = Number(yearlyData[year].endBalance.toFixed(2)); });return { yearlyData, monthlyData, totalInterest: Number(totalInterest.toFixed(2)), numPayments: paymentCount, firstPaymentDate, lastPaymentDate }; }function updateUI(form, monthlyPayment, amortizationData) { const { yearlyData, monthlyData, totalInterest, numPayments, firstPaymentDate, lastPaymentDate } = amortizationData;dynamicRateEl.textContent = form.annualRate.toFixed(2); summaryNumPaymentsEl.textContent = numPayments; summaryMonthlyPaymentEl.textContent = formatCurrency(monthlyPayment); summaryTotalInterestEl.textContent = formatCurrency(totalInterest); summaryTotalCostEl.textContent = formatCurrency(Number((form.loanAmount + totalInterest).toFixed(2))); summaryPayoffDateEl.textContent = lastPaymentDate.toLocaleString('default', { month: 'long', year: 'numeric' }); firstPaymentDateEl.textContent = firstPaymentDate.toLocaleString('default', { month: 'long', year: 'numeric' }); lastPaymentDateEl.textContent = lastPaymentDate.toLocaleString('default', { month: 'long', year: 'numeric' });const totalPrincipal = Number((form.loanAmount - (monthlyData[monthlyData.length - 1]?.balance || 0)).toFixed(2)); legendBalanceEl.textContent = formatCurrency(monthlyData[monthlyData.length - 1]?.balance || 0); legendPrincipalEl.textContent = formatCurrency(totalPrincipal); legendInterestEl.textContent = formatCurrency(totalInterest);updateAmortizationGraph(yearlyData, form.loanAmount, totalInterest); updateAmortizationTable(yearlyData); }function updateAmortizationGraph(yearlyData, loanAmount, totalInterest) { const svg = document.getElementById('amortization-chart-svg'); svg.innerHTML = ''; if (Object.keys(yearlyData).length === 0 || loanAmount <= 0) { svg.innerHTML = 'No data to display'; return; }const allMonths = Object.values(yearlyData).flatMap(y => y.months); if (allMonths.length === 0) return;const width = 360; const height = 220, m = { top: 20, right: 20, bottom: 35, left: 50 }; const w = width - m.left - m.right, h = height - m.top - m.bottom; const maxY = Math.max(loanAmount, totalInterest, 1);const g = document.createElementNS("http://www.w3.org/2000/svg", "g"); g.setAttribute("transform", `translate(${m.left},${m.top})`); svg.appendChild(g);const xScale = i => (i / (allMonths.length - 1)) * w; const yScale = v => h - (v / maxY) * h;const createPath = (data, color) => { const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); let d = `M0,${yScale(data[0])}`; for (let i = 1; i < data.length; i++) { if (isFinite(data[i]) && data[i] >= 0) { d += ` L${xScale(i)},${yScale(data[i])}`; } } path.setAttribute('d', d); path.setAttribute('class', 'line'); path.style.stroke = color; path.style.strokeWidth = '2.5'; path.style.opacity = '0.9'; return path; };let cumulativePrincipal = 0, cumulativeInterest = 0; const balanceData = allMonths.map(d => d.balance < 0 ? 0 : d.balance); const principalData = allMonths.map(d => { cumulativePrincipal += d.principal; return Math.min(cumulativePrincipal, maxY); }); const interestData = allMonths.map(d => { cumulativeInterest += d.interest; return Math.min(cumulativeInterest, maxY); });[createPath(balanceData, 'var(--br-chart-balance)'), createPath(principalData, 'var(--br-chart-principal)'), createPath(interestData, 'var(--br-chart-interest)')].forEach(path => g.appendChild(path));// Y-axis grid and labels for (let i = 0; i <= 5; i++) { const y = h * (i / 5); const line = document.createElementNS("http://www.w3.org/2000/svg", "line"); line.setAttribute('x1', 0); line.setAttribute('x2', w); line.setAttribute('y1', y); line.setAttribute('y2', y); line.setAttribute('class', 'grid'); g.appendChild(line); const text = document.createElementNS("http://www.w3.org/2000/svg", "text"); text.setAttribute('x', -10); text.setAttribute('y', y + 4); text.setAttribute('class', 'axis-label'); text.setAttribute('text-anchor', 'end'); text.textContent = `$${(maxY * (1 - i / 5) / 1000).toFixed(0)}k`; g.appendChild(text); }// X-axis grid and labels const yearKeys = Object.keys(yearlyData).sort(); const step = Math.max(1, Math.ceil(yearKeys.length / 6)); for (let i = 0; i < yearKeys.length; i += step) { const year = yearKeys[i]; const monthIndex = allMonths.findIndex(d => d.date.getFullYear() == year); if (monthIndex < 0) continue; const x = xScale(monthIndex); const line = document.createElementNS("http://www.w3.org/2000/svg", "line"); line.setAttribute('x1', x); line.setAttribute('x2', x); line.setAttribute('y1', 0); line.setAttribute('y2', h); line.setAttribute('class', 'grid'); g.appendChild(line); const text = document.createElementNS("http://www.w3.org/2000/svg", "text"); text.setAttribute('x', x); text.setAttribute('y', h + 20); text.setAttribute('class', 'axis-label'); text.setAttribute('text-anchor', 'middle'); text.textContent = year; g.appendChild(text); } }function updateAmortizationTable(yearlyData) { amortizationTableBody.innerHTML = ''; Object.keys(yearlyData).sort().forEach(year => { const yearData = yearlyData[year]; const details = document.createElement('details'); details.innerHTML = ` ${year} ${formatCurrency(yearData.totalPrincipal)} ${formatCurrency(yearData.totalInterest)} ${formatCurrency(yearData.endBalance)}
${yearData.months.map(row => ` `).join('')}
MonthPrincipalInterestRemaining Balance
${row.date.toLocaleString('default', { month: 'long' })}${formatCurrency(row.principal)}${formatCurrency(row.interest)}${formatCurrency(row.balance)}
`; amortizationTableBody.appendChild(details); }); }calculateAndDisplay(); });

Features of Our Amortization Calculator

Visual Loan Breakdown

See exactly where your money goes with an interactive chart showing the breakdown of principal versus interest over time.

Detailed Schedule

Generate a complete, year-by-year and month-by-month loan amortization schedule that you can view, print, or export.

Extra Payment Modeling

Discover how making extra monthly, yearly, or one-time payments can help you pay off your loan faster and save thousands.

Understanding Your Loan with Our Amortization Calculator

Taking out a loan, especially a mortgage, is one of the biggest financial decisions you'll ever make. Understanding how that loan works is crucial. Our free **Amortization Calculator** is designed to give you a clear, detailed picture of your loan over its entire life. It shows you precisely how each monthly payment is split between paying down your principal (the money you borrowed) and paying the interest (the cost of borrowing).

A chart showing how an amortization calculator breaks down principal and interest payments over the life of a loan.

How to Use the Loan Amortization Schedule Calculator

Our tool makes it simple to generate a loan amortization schedule. Here’s how:

  • Enter Your Loan Details: Input your total loan amount, the annual interest rate, the loan term (in years), and the start date of your loan.
  • Model Extra Payments (Optional): Want to see how you can pay your loan off faster? Use the optional fields to add extra monthly, yearly, or even a one-time lump-sum payment to your plan.
  • Analyze Your Results: Instantly, our calculator will show you a summary, including your monthly payment, total interest paid, and your final payoff date. You can explore the interactive chart or view the detailed, printable schedule to see your loan balance decrease over time.

What Is Amortization and Why Is It Important?

Amortization is the process of spreading out a loan into a series of fixed payments over time. As the financial experts at Investopedia explain, with each payment, you pay off the interest accrued for that period first, and the remaining amount goes toward reducing your principal balance. Our **mortgage amortization** tool visualizes this process perfectly. In the early years of your loan, a larger portion of your payment goes to interest. As you continue to make payments, more and more of your money goes toward the principal, helping you build equity faster.

Understanding this is key to smart financial planning. By using our **extra payment calculator** feature, you can see how even small additional payments can dramatically reduce the total interest you pay and shorten your loan term by years. Before you get a loan, be sure to check your financial health with our Debt-to-Income Ratio Calculator.

Frequently Asked Questions about our Amortization Calculator

What types of loans can I use this amortization calculator for?

This calculator is perfect for any fixed-rate installment loan where payments are made regularly. This most commonly includes home mortgages (e.g., 15-year or 30-year fixed), auto loans, and personal loans. It is not designed for interest-only loans or loans with variable interest rates.

How does making an extra payment help me?

When you make an extra payment, that money is typically applied directly to your principal balance. This has two major benefits: first, it reduces the total amount of interest you'll pay over the life of the loan, and second, it helps you pay off the entire loan faster, sometimes by several years. Our extra payment calculator feature lets you see this effect instantly.

Can I export or print the loan amortization schedule?

Yes. Once you generate your results, you can navigate to the "Schedule" tab. There you will find options to "Export as CSV" for use in spreadsheet software like Excel or Google Sheets, and a "Print Schedule" button that will format the entire amortization table for clean printing.